<commit_before>/**
 * Curriculum inventory management (cim) view components.
 *
 * Defines the following namespaces:
 *     ilios.cim.view
 *
 *  Dependencies:
 *     application/views/scripts/ilios_base.js
 *     ilios_i18nVendor
 *     YUI Dom/Event/Element libs
 *     YUI Cookie lib
 *     application/views/curriculum_inventory/js/ilios.cim.model.js
 *     application/views/curriculum_inventory/js/ilios.cim.views.js
 */
(function () {

    ilios.namespace('cim.view');

    var Lang = YAHOO.lang,
        Dom = YAHOO.util.Dom,
        Element = YAHOO.util.Element,
        Event = YAHOO.util.Event,
        Cookie = YAHOO.util.Cookie;

    var StatusView = function (oConfig) {
        StatusView.superclass.constructor.call(this, document.createElement('div'), oConfig);
    };

    Lang.extend(StatusView, Element, {
        initAttributes: function (config) {
            StatusView.superclass.initAttributes.call(this, config);

            var container = this.get('element');

            this.setAttributeConfig('progressEl', {
                writeOnce: true,
                value: container.appendChild(document.createElement('div'))
            });

            this.setAttributeConfig('messageEl', {
                writeOnce: true,
                value: container.appendChild(document.createElement('span'))
            });

            this.setAttributeConfig('message', {
                validator: Lang.isString,
                method: function (value) {
                    var el = this.get('messageEl');
                    if (el) {
                        el.innerHTML = value;
                    }
                },
                value: ''
            });
        },
        render: function (parentEl) {
            parentEl = Dom.get(parentEl);
            var containerEl = this.get('element');
            this.addClass('status-view-container');
            this.setStyle('display', 'none');
            var progressEl = this.get('progressEl');
            Dom.addClass(progressEl, 'in-progress-indicator');
            Dom.setStyle(progressEl, 'display', 'none');
            parentEl.appendChild(containerEl);
        },
        reset: function () {
            this.show('', false)
        },
        show: function (message, showProgressIndicator) {
            showProgressIndicator = showProgressIndicator || false;
            Dom.setStyle(this.get('progressEl'), 'display', (showProgressIndicator ? 'inline-block' : 'none'));
            this.set('message', message);
            this.setStyle('display', 'block');
        },
        hide: function () {
            this.setStyle('display', 'none');
        }
    });

    ilios.cim.view.StatusView = StatusView;

    /**
     * The view for a given report model.
     * @namespace ilios.cim.view
     * @class ReportView
     * @constructor
     * @extends YAHOO.util.Element
     * @param {ilios.cim.model.ReportModel} model The report model.
     * @param {Object} oConfig A configuration object.
     */
    var ReportView = function (model, oConfig) {
        ReportView.superclass.constructor.call(this, document.getElementById('report-details-view-container'));

        this.config = oConfig;
        this.model = model;

        // subscribe to model changes
        this.model.subscribe('nameChange', this.onNameChange, {}, this);
        this.model.subscribe('descriptionChange', this.onDescriptionChange, {}, this);
        this.model.subscribe('startDateChange', this.onStartDateChange, {}, this);
        this.model.subscribe('endDateChange', this.onEndDateChange, {}, this);
        this.model.subscribe('isFinalizedChange', this.onStatusChange, {}, this);
    };

    Lang.extend(ReportView, Element, {
        _downloadIntervalTimer: null,
        _exportIntervalTimer: null,
        _blockUIForDownload: function () {
            var token = (new Date()).getTime();
            (new Element('report-details-view-download-button')).set('disabled', true);
            this.fireEvent('downloadStarted');
            this.set('downloadToken', token);
            this._downloadIntervalTimer = Lang.later(1000, this, function () {
                var cookieValue = Cookie.get('download-token');
                if (cookieValue == token) {
                    this._finishDownload();
                }
            }, [], true);
        },
        _finishDownload: function () {
            this._downloadIntervalTimer.cancel();
            Cookie.remove('fileDownloadToken');
            (new Element('report-details-view-download-button')).set('disabled', false);
            this.fireEvent('downloadFinished');
        },
        _blockUIForExport: function () {
            var token = (new Date()).getTime();
            (new Element('report-details-view-export-button')).set('disabled', true);
            this.fireEvent('exportStarted');
            this.set('exportToken', token);
            this._exportIntervalTimer = Lang.later(1000, this, function () {
                var cookieValue = Cookie.get('download-token');
                if (cookieValue == token) {
                    this._finishExport();
                }
            }, [], true);
        },
        _finishExport: function () {
            this._exportIntervalTimer.cancel();
            Cookie.remove('fileExportToken');
            (new Element('report-details-view-export-button')).set('disabled', false);
            this.fireEvent('exportFinished');
        },
        initAttributes : function (config) {
            ReportView.superclass.initAttributes.call(this, config);

            this.setAttributeConfig('nameEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-name')
            });
            this.setAttributeConfig('academicYearEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-academic-year')
            });
            this.setAttributeConfig('startDateEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-start-date')
            });
            this.setAttributeConfig('endDateEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-end-date')
            });
            this.setAttributeConfig('descriptionEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-description')
            });
            this.setAttributeConfig('programEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-program')
            });
            this.setAttributeConfig('reportExportIdEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-export-report-id')
            });
            this.setAttributeConfig('reportDownloadIdEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-download-report-id')
            });
            this.setAttributeConfig('downloadTokenEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-download-download-token')
            });
            this.setAttributeConfig('exportTokenEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-export-download-token')
            });
            this.setAttributeConfig('statusEl', {
                writeOnce: true,
                value: Dom.get('report-details-status')
            });

            this.setAttributeConfig('name', {
                validator: Lang.isString,
                method: function (value) {
                    var el = this.get('nameEl');
                    if (el) {
                        el.innerHTML = value;
                    }
                },
                value: ''
            });
            this.setAttributeConfig('academicYear', {
                validator: Lang.isString,
                method: function (value) {
                    var el = this.get('academicYearEl');
                    if (el) {
                        el.innerHTML = value;
                    }
                },
                value: ''
            });
            this.setAttributeConfig('startDate', {
                validator: Lang.isString,
                method: function (value) {
                    var el = this.get('startDateEl');
                    if (el) {
                        el.innerHTML = value;
                    }
                },
                value: ''
            });
            this.setAttributeConfig('endDate', {
                validator: Lang.isString,
                method: function (value) {
                    var el = this.get('endDateEl');
                    if (el) {
                        el.innerHTML = value;
                    }
                },
                value: ''
            });
            this.setAttributeConfig('description', {
                validator: Lang.isString,
                method: function (value) {
                    var el = this.get('descriptionEl');
                    if (el) {
                        el.innerHTML = value;
                    }
                },
                value: ''
            });
            this.setAttributeConfig('program', {
                validator: Lang.isObject,
                method: function (value) {
                    var el = this.get('programEl');
                    if (el) {
                        el.innerHTML = value.title + " (" + value.short_title + ")"
                    }
                }
            });
            this.setAttributeConfig('reportId', {
                validator: Lang.isString,
                method: function (value) {
                    var el = this.get('reportExportIdEl');
                    if (el) {
                        el.value = value;
                    }
                    el = this.get('reportDownloadIdEl');
                    if (el) {
                        el.value = value;
                    }
                },
                value: ''
            });
            this.setAttributeConfig('downloadToken', {
                method: function (value) {
                    var el = this.get('downloadTokenEl');
                    if (el) {
                        el.value = value;
                    }
                }
            });
            this.setAttributeConfig('exportToken', {
                method: function (value) {
                    var el = this.get('exportTokenEl');
                    if (el) {
                        el.value = value;
                    }
                }
            });

            this.setAttributeConfig('status', {
                method: function (value) {
                    var el;
                    if (value) {
                        el = this.get('statusEl');
                        Dom.removeClass(el, 'is-draft');
                        Dom.addClass(el, 'is-locked');
                        el.innerHTML = ilios_i18nVendor.getI18NString('general.terms.finalized');
                        // enabled/show buttons and forms
                        (new Element('report-details-view-download-button')).set('disabled', false);
                        Dom.removeClass('report-details-view-download-form', 'hidden');
                        // disabled/hide buttons and forms
                        el = new Element('report-details-view-edit-button');
                        el.set('disabled', false);
                        el.addClass('hidden');
                        el = new Element('report-details-view-delete-button');
                        el.set('disabled', false);
                        el.addClass('hidden');
                        el = new Element('report-details-view-delete-button');
                        el.set('disabled', false);
                        el.addClass('hidden');
                        el = new Element('report-details-view-finalize-button');
                        el.set('disabled', false);
                        el.addClass('hidden');
                        el = new Element('report-details-view-export-button');
                        el.set('disabled', false);
                        Dom.addClass('report-details-view-export-form', 'hidden');
                    } else {
                        el = this.get('statusEl');
                        Dom.removeClass(el, 'is-locked');
                        Dom.addClass(el, 'is-draft');
                        el.innerHTML = ilios_i18nVendor.getI18NString('general.terms.draft');
                        // enabled/show buttons and forms
                        el = new Element('report-details-view-edit-button');
                        el.set('disabled', false);
                        el.removeClass('hidden');
                        el = new Element('report-details-view-finalize-button');
                        el.set('disabled', false);
                        el.removeClass('hidden');
                        el = new Element('report-details-view-delete-button');
                        el.set('disabled', false);
                        el.removeClass('hidden');
                        el = new Element('report-details-view-export-button');
                        el.set('disabled', false);
                        Dom.removeClass('report-details-view-export-form', 'hidden');
                        // disabled/hide buttons and forms
                        (new Element('report-details-view-download-button')).set('disabled', true);
                        Dom.addClass('report-details-view-download-form', 'hidden');
                    }
                }
            });

            // create custom events
            this.createEvent('exportStarted');
            this.createEvent('exportFinished');
            this.createEvent('downloadStarted');
            this.createEvent('downloadFinished');
            this.createEvent('exportStarted');
            this.createEvent('exportFinished');
            this.createEvent('finalizeStarted');
            this.createEvent('finalizeSucceeded');
            this.createEvent('finalizeFailed');

            // subscribe internally to some custom events
            this.subscribe('finalizeStarted', function () {
                (new Element('report-details-view-edit-button')).set('disabled', true);
                (new Element('report-details-view-finalize-button')).set('disabled', true);
                (new Element('report-details-view-delete-button')).set('disabled', true);
                (new Element('report-details-view-export-button')).set('disabled', true);
            }, this, true);
            this.subscribe('finalizeFailed', function () {
                (new Element('report-details-view-edit-button')).set('disabled', false);
                (new Element('report-details-view-finalize-button')).set('disabled', false);
                (new Element('report-details-view-delete-button')).set('disabled', false);
                (new Element('report-details-view-export-button')).set('disabled', false);
            }, this, true);
        },
        render: function () {

            this.set('name', this.model.get('name'));
            this.set('description', this.model.get('description'));
            this.set('academicYear', this.model.get('academicYear'));
            this.set('startDate', this.model.get('startDate'));
            this.set('endDate', this.model.get('endDate'));
            this.set('program', this.model.get('program'));
            this.set('reportId', this.model.get('id'));
            this.set('status', this.model.get('isFinalized'));

            //
            // wire dialog buttons
            //
            if (! this.model.get('isFinalized')) {
                Event.addListener('report-details-view-edit-button', 'click', function(event) {
                    if (! this.editReportDialog) {
                        this.editReportDialog = new ilios.cim.widget.EditReportDialog('edit_report_dialog', this.model);
                    }
                    this.editReportDialog.show();
                    Event.stopEvent(event);
                    return false;
                }, {}, this);
                Event.addListener('report-details-view-export-form', 'submit', this._blockUIForExport, {}, this);

                Event.addListener('report-details-view-finalize-button', 'click', function (event, args) {
                        var continueStr = ilios_i18nVendor.getI18NString('general.phrases.want_to_continue');
                        var yesStr = ilios_i18nVendor.getI18NString('general.terms.yes');
                        ilios.alert.inform(continueStr, yesStr, function (event, args) {
                            var model = args.model;
                            var url = args.url;
                            var view = args.view;
                            var postData = 'report_id=' + encodeURIComponent(model.get('id'));
                            var callback = {
                                success: function (o) {
                                    var response, msg;
                                    try {
                                        response = YAHOO.lang.JSON.parse(o.responseText);
                                    } catch (e) {
                                        view.fireEvent('finalizeFailed');
                                        ilios.global.defaultAJAXFailureHandler(null, e);
                                        return;
                                    }
                                    if (response.error) {
                                        view.fireEvent('finalizeFailed');
                                        msg = ilios_i18nVendor.getI18NString('curriculum_inventory.finalize.error.general');
                                        ilios.alert.alert(msg + ": " + response.error);
                                        return;
                                    }
                                    view.fireEvent('finalizeSucceeded');
                                    model.set('isFinalized', true);
                                },
                                failure: function (o) {
                                    view.fireEvent('finalizeFailed');
                                    ilios.global.defaultAJAXFailureHandler(o);
                                }
                            };

                            this.hide(); // hide the calling dialog

                            view.fireEvent('finalizeStarted');
                            YAHOO.util.Connect.initHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
                            YAHOO.util.Connect.asyncRequest("POST", url, callback, postData);
                        }, args);
                    }, {
                        model: this.model,
                        url: this.config.finalizeUrl,
                        view: this
                    },
                    this);
            }
            Event.addListener('report-details-view-toggle', 'click', function (event) {
                ilios.utilities.toggle('report-details-view-content-wrapper', this);
                Event.stopEvent(event);
                return false;
            });
            Event.addListener('report-details-view-download-form', 'submit', this._blockUIForDownload, {}, this);
        },
        show: function () {
            this.setStyle('display', 'block');
        },
        onNameChange: function (evObj) {
            this.set('name', evObj.newValue);
        },

        onDescriptionChange: function (evObj) {
            this.set('description', evObj.newValue);
        },
        onStartDateChange: function (evObj) {
            this.set('startDate', evObj.newValue);
        },
        onEndDateChange: function (evObj) {
            this.set('endDate', evObj.newValue);
        },
        onStatusChange: function (evObj) {
            this.set('status', evObj.newValue);
        }
    });
    ilios.cim.view.ReportView = ReportView;
}());
<commit_msg>refacted report view for better event wiring and improved reusability of button locking/display toggling.<commit_after>/**
 * Curriculum inventory management (cim) view components.
 *
 * Defines the following namespaces:
 *     ilios.cim.view
 *
 *  Dependencies:
 *     application/views/scripts/ilios_base.js
 *     ilios_i18nVendor
 *     YUI Dom/Event/Element libs
 *     YUI Cookie lib
 *     application/views/curriculum_inventory/js/ilios.cim.model.js
 *     application/views/curriculum_inventory/js/ilios.cim.views.js
 */
(function () {

    ilios.namespace('cim.view');

    var Lang = YAHOO.lang,
        Dom = YAHOO.util.Dom,
        Element = YAHOO.util.Element,
        Event = YAHOO.util.Event,
        Cookie = YAHOO.util.Cookie;

    var StatusView = function (oConfig) {
        StatusView.superclass.constructor.call(this, document.createElement('div'), oConfig);
    };

    Lang.extend(StatusView, Element, {
        initAttributes: function (config) {
            StatusView.superclass.initAttributes.call(this, config);

            var container = this.get('element');

            this.setAttributeConfig('progressEl', {
                writeOnce: true,
                value: container.appendChild(document.createElement('div'))
            });

            this.setAttributeConfig('messageEl', {
                writeOnce: true,
                value: container.appendChild(document.createElement('span'))
            });

            this.setAttributeConfig('message', {
                validator: Lang.isString,
                method: function (value) {
                    var el = this.get('messageEl');
                    if (el) {
                        el.innerHTML = value;
                    }
                },
                value: ''
            });
        },
        render: function (parentEl) {
            parentEl = Dom.get(parentEl);
            var containerEl = this.get('element');
            this.addClass('status-view-container');
            this.setStyle('display', 'none');
            var progressEl = this.get('progressEl');
            Dom.addClass(progressEl, 'in-progress-indicator');
            Dom.setStyle(progressEl, 'display', 'none');
            parentEl.appendChild(containerEl);
        },
        reset: function () {
            this.show('', false)
        },
        show: function (message, showProgressIndicator) {
            showProgressIndicator = showProgressIndicator || false;
            Dom.setStyle(this.get('progressEl'), 'display', (showProgressIndicator ? 'inline-block' : 'none'));
            this.set('message', message);
            this.setStyle('display', 'block');
        },
        hide: function () {
            this.setStyle('display', 'none');
        }
    });

    ilios.cim.view.StatusView = StatusView;

    /**
     * The view for a given report model.
     * @namespace ilios.cim.view
     * @class ReportView
     * @constructor
     * @extends YAHOO.util.Element
     * @param {ilios.cim.model.ReportModel} model The report model.
     * @param {Object} oConfig A configuration object.
     */
    var ReportView = function (model, oConfig) {
        ReportView.superclass.constructor.call(this, document.getElementById('report-details-view-container'));

        this.config = oConfig;
        this.model = model;

        // subscribe to model changes
        this.model.subscribe('nameChange', this.onNameChange, {}, this);
        this.model.subscribe('descriptionChange', this.onDescriptionChange, {}, this);
        this.model.subscribe('startDateChange', this.onStartDateChange, {}, this);
        this.model.subscribe('endDateChange', this.onEndDateChange, {}, this);
        this.model.subscribe('isFinalizedChange', this.onStatusChange, {}, this);

        // create custom events
        this.createEvent('exportStarted');
        this.createEvent('exportFinished');
        this.createEvent('downloadStarted');
        this.createEvent('downloadFinished');
        this.createEvent('exportStarted');
        this.createEvent('exportFinished');
        this.createEvent('finalizeStarted');
        this.createEvent('finalizeSucceeded');
        this.createEvent('finalizeFailed');
        this.createEvent('deleteStarted');
        this.createEvent('deleteSucceeded');
        this.createEvent('deleteFailed');

        // subscribe to own events
        this.subscribe('finalizeStarted', function () {
            this._lockDraftModeButtons();
        }, {}, this);
        this.subscribe('finalizeFailed', function () {
            this._unlockDraftModeButtons();
        }, {}, this);
        this.subscribe('deleteStarted', function () {
            this._lockDraftModeButtons();
        }, {}, this);
        this.subscribe('deleteFailed', function () {
            this._unlockDraftModeButtons();
        }, {}, this);
    };

    Lang.extend(ReportView, Element, {
        _downloadIntervalTimer: null,
        _exportIntervalTimer: null,
        _blockUIForDownload: function () {
            var token = (new Date()).getTime();
            (new Element('report-details-view-download-button')).set('disabled', true);
            this.fireEvent('downloadStarted');
            this.set('downloadToken', token);
            this._downloadIntervalTimer = Lang.later(1000, this, function () {
                var cookieValue = Cookie.get('download-token');
                if (cookieValue == token) {
                    this._finishDownload();
                }
            }, [], true);
        },
        _finishDownload: function () {
            this._downloadIntervalTimer.cancel();
            Cookie.remove('fileDownloadToken');
            (new Element('report-details-view-download-button')).set('disabled', false);
            this.fireEvent('downloadFinished');
        },
        _blockUIForExport: function () {
            var token = (new Date()).getTime();
            (new Element('report-details-view-export-button')).set('disabled', true);
            this.fireEvent('exportStarted');
            this.set('exportToken', token);
            this._exportIntervalTimer = Lang.later(1000, this, function () {
                var cookieValue = Cookie.get('download-token');
                if (cookieValue == token) {
                    this._finishExport();
                }
            }, [], true);
        },
        _finishExport: function () {
            this._exportIntervalTimer.cancel();
            Cookie.remove('fileExportToken');
            (new Element('report-details-view-export-button')).set('disabled', false);
            this.fireEvent('exportFinished');
        },

        _lockDraftModeButtons: function () {
            (new Element('report-details-view-edit-button')).set('disabled', true);
            (new Element('report-details-view-finalize-button')).set('disabled', true);
            (new Element('report-details-view-delete-button')).set('disabled', true);
            (new Element('report-details-view-export-button')).set('disabled', true);
        },
        _unlockDraftModeButtons: function () {
            (new Element('report-details-view-edit-button')).set('disabled', false);
            (new Element('report-details-view-finalize-button')).set('disabled', false);
            (new Element('report-details-view-delete-button')).set('disabled', false);
            (new Element('report-details-view-export-button')).set('disabled', false);
        },
        _hideDraftModeButtons: function () {
            Dom.addClass('report-details-view-edit-button', 'hidden');
            Dom.addClass('report-details-view-finalize-button', 'hidden');
            Dom.addClass('report-details-view-delete-button', 'hidden');
            Dom.addClass('report-details-view-export-form', 'hidden');
        },
        _showDraftModeButtons: function () {
            Dom.removeClass('report-details-view-edit-button', 'hidden');
            Dom.removeClass('report-details-view-finalize-button', 'hidden');
            Dom.removeClass('report-details-view-delete-button', 'hidden');
            Dom.removeClass('report-details-view-export-form', 'hidden');
        },
        _lockFinalizedModeButtons: function () {
            (new Element('report-details-view-download-button')).set('disabled', true);
        },
        _unlockFinalizedModeButtons: function () {
            (new Element('report-details-view-download-button')).set('disabled', false);
        },
        _hideFinalizedModeButtons: function () {
            Dom.addClass('report-details-view-download-form', 'hidden');
        },
        _showFinalizedModeButtons: function () {
            Dom.removeClass('report-details-view-download-form', 'hidden');
        },

        initAttributes : function (config) {
            ReportView.superclass.initAttributes.call(this, config);

            this.setAttributeConfig('nameEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-name')
            });
            this.setAttributeConfig('academicYearEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-academic-year')
            });
            this.setAttributeConfig('startDateEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-start-date')
            });
            this.setAttributeConfig('endDateEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-end-date')
            });
            this.setAttributeConfig('descriptionEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-description')
            });
            this.setAttributeConfig('programEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-program')
            });
            this.setAttributeConfig('reportExportIdEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-export-report-id')
            });
            this.setAttributeConfig('reportDownloadIdEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-download-report-id')
            });
            this.setAttributeConfig('downloadTokenEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-download-download-token')
            });
            this.setAttributeConfig('exportTokenEl', {
                writeOnce: true,
                value: Dom.get('report-details-view-export-download-token')
            });
            this.setAttributeConfig('statusEl', {
                writeOnce: true,
                value: Dom.get('report-details-status')
            });

            this.setAttributeConfig('name', {
                validator: Lang.isString,
                method: function (value) {
                    var el = this.get('nameEl');
                    if (el) {
                        el.innerHTML = value;
                    }
                },
                value: ''
            });
            this.setAttributeConfig('academicYear', {
                validator: Lang.isString,
                method: function (value) {
                    var el = this.get('academicYearEl');
                    if (el) {
                        el.innerHTML = value;
                    }
                },
                value: ''
            });
            this.setAttributeConfig('startDate', {
                validator: Lang.isString,
                method: function (value) {
                    var el = this.get('startDateEl');
                    if (el) {
                        el.innerHTML = value;
                    }
                },
                value: ''
            });
            this.setAttributeConfig('endDate', {
                validator: Lang.isString,
                method: function (value) {
                    var el = this.get('endDateEl');
                    if (el) {
                        el.innerHTML = value;
                    }
                },
                value: ''
            });
            this.setAttributeConfig('description', {
                validator: Lang.isString,
                method: function (value) {
                    var el = this.get('descriptionEl');
                    if (el) {
                        el.innerHTML = value;
                    }
                },
                value: ''
            });
            this.setAttributeConfig('program', {
                validator: Lang.isObject,
                method: function (value) {
                    var el = this.get('programEl');
                    if (el) {
                        el.innerHTML = value.title + " (" + value.short_title + ")"
                    }
                }
            });
            this.setAttributeConfig('reportId', {
                validator: Lang.isString,
                method: function (value) {
                    var el = this.get('reportExportIdEl');
                    if (el) {
                        el.value = value;
                    }
                    el = this.get('reportDownloadIdEl');
                    if (el) {
                        el.value = value;
                    }
                },
                value: ''
            });
            this.setAttributeConfig('downloadToken', {
                method: function (value) {
                    var el = this.get('downloadTokenEl');
                    if (el) {
                        el.value = value;
                    }
                }
            });
            this.setAttributeConfig('exportToken', {
                method: function (value) {
                    var el = this.get('exportTokenEl');
                    if (el) {
                        el.value = value;
                    }
                }
            });

            this.setAttributeConfig('isFinalized', {
                method: function (value) {
                    var el;
                    if (value) {
                        el = this.get('statusEl');
                        Dom.removeClass(el, 'is-draft');
                        Dom.addClass(el, 'is-locked');
                        el.innerHTML = ilios_i18nVendor.getI18NString('general.terms.finalized');
                        this._lockDraftModeButtons();
                        this._hideDraftModeButtons();
                        this._unlockFinalizedModeButtons();
                        this._showFinalizedModeButtons();
                    } else {
                        el = this.get('statusEl');
                        Dom.removeClass(el, 'is-locked');
                        Dom.addClass(el, 'is-draft');
                        el.innerHTML = ilios_i18nVendor.getI18NString('general.terms.draft');
                        this._unlockDraftModeButtons();
                        this._showDraftModeButtons();
                        this._lockFinalizedModeButtons();
                        this._hideFinalizedModeButtons();
                    }
                }
            });
        },
        render: function () {

            this.set('name', this.model.get('name'));
            this.set('description', this.model.get('description'));
            this.set('academicYear', this.model.get('academicYear'));
            this.set('startDate', this.model.get('startDate'));
            this.set('endDate', this.model.get('endDate'));
            this.set('program', this.model.get('program'));
            this.set('reportId', this.model.get('id'));
            this.set('isFinalized', this.model.get('isFinalized'));

            //
            // wire and show applicable dialog buttons
            //

            // always wire the finalized mode buttons first
            Event.addListener('report-details-view-toggle', 'click', function (event) {
                ilios.utilities.toggle('report-details-view-content-wrapper', this);
                Event.stopEvent(event);
                return false;
            });
            Event.addListener('report-details-view-download-form', 'submit', this._blockUIForDownload, {}, this);

            // if the report view gets rendered in draft mode then wire all of its buttons too.
            if (! this.get('status')) {
                Event.addListener('report-details-view-edit-button', 'click', function(event) {
                    if (! this.editReportDialog) {
                        this.editReportDialog = new ilios.cim.widget.EditReportDialog('edit_report_dialog', this.model);
                    }
                    this.editReportDialog.show();
                    Event.stopEvent(event);
                    return false;
                }, {}, this);
                Event.addListener('report-details-view-export-form', 'submit', this._blockUIForExport, {}, this);

                Event.addListener('report-details-view-finalize-button', 'click', function (event, args) {
                    var continueStr = ilios_i18nVendor.getI18NString('general.phrases.want_to_continue');
                    var yesStr = ilios_i18nVendor.getI18NString('general.terms.yes');
                    ilios.alert.inform(continueStr, yesStr, function (event, args) {
                        var model = args.model;
                        var url = args.url;
                        var view = args.view;
                        var postData = 'report_id=' + encodeURIComponent(model.get('id'));
                        var callback = {
                            success: function (o) {
                                var response, msg;
                                try {
                                    response = YAHOO.lang.JSON.parse(o.responseText);
                                } catch (e) {
                                    view.fireEvent('finalizeFailed');
                                    ilios.global.defaultAJAXFailureHandler(null, e);
                                    return;
                                }
                                if (response.error) {
                                    view.fireEvent('finalizeFailed');
                                    msg = ilios_i18nVendor.getI18NString('curriculum_inventory.finalize.error.general');
                                    ilios.alert.alert(msg + ": " + response.error);
                                    return;
                                }
                                model.set('isFinalized', true);
                                view.fireEvent('finalizeSucceeded');
                            },
                            failure: function (o) {
                                view.fireEvent('finalizeFailed');
                                ilios.global.defaultAJAXFailureHandler(o);
                            }
                        };

                        this.hide(); // hide the calling dialog

                        view.fireEvent('finalizeStarted');
                        YAHOO.util.Connect.initHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
                        YAHOO.util.Connect.asyncRequest("POST", url, callback, postData);
                    }, args);
                }, {
                    model: this.model,
                    url: this.config.finalizeUrl,
                    view: this
                },
                this);
            }

        },
        show: function () {
            this.setStyle('display', 'block');
        },
        onNameChange: function (evObj) {
            this.set('name', evObj.newValue);
        },

        onDescriptionChange: function (evObj) {
            this.set('description', evObj.newValue);
        },
        onStartDateChange: function (evObj) {
            this.set('startDate', evObj.newValue);
        },
        onEndDateChange: function (evObj) {
            this.set('endDate', evObj.newValue);
        },
        onStatusChange: function (evObj) {
            this.set('isFinalized', evObj.newValue);
        }
    });
    ilios.cim.view.ReportView = ReportView;
}());
<|endoftext|>


<commit_before>define(["dojo/number", "dojo/_base/lang", "dojo/i18n"],
  function(dojoNumber, lang, i18n) {

    /*=====
     number.__FormatOptions = declare(null, {
     // pattern: String?
     //		override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
     //		with this string.  Default value is based on locale.  Overriding this property will defeat
     //		localization.  Literal characters in patterns are not supported.
     // type: String?
     //		choose a format type based on the locale from the following:
     //		decimal, scientific (not yet supported), percent, currency. decimal by default.
     // places: Number?
     //		fixed number of decimal places to show.  This overrides any
     //		information in the provided pattern.
     // round: Number?
     //		5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
     //		means do not round.
     // locale: String?
     //		override the locale used to determine formatting rules
     // fractional: Boolean?
     //		If false, show no decimal places, overriding places and pattern settings.
     // group: String?
     //   This string is used as group separator instead of the locale defined symbol, if given.
     });
     =====*/

    // summary:
    //   We take over the dojo/number functionality, to add the possibility in formatting to change the group
    //   symbol. It is possible to add a String "group" property to the FormatOptions
    var number = lang.delegate(dojoNumber, {

      format: function(/*Number*/ value, /*number.__FormatOptions?*/ options) {
        // summary:
        //		Format a Number as a String, using locale-specific settings
        // description:
        //		Create a string from a Number using a known localized pattern.
        //		Formatting patterns appropriate to the locale are chosen from the
        //		[Common Locale Data Repository](http://unicode.org/cldr) as well as the appropriate symbols and
        //		delimiters.
        //		If value is Infinity, -Infinity, or is not a valid JavaScript number, return null.
        // value:
        //		the number to be formatted

        options = lang.mixin({}, options || {});
        var locale = i18n.normalizeLocale(options.locale),
          bundle = i18n.getLocalization("dojo.cldr", "number", locale);
        options.customs = bundle || {};
        var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];
        if (options.group) {
          options.customs.group = options.group;
        }
        if(isNaN(value) || Math.abs(value) == Infinity){ return null; } // null
        return this._applyPattern(value, pattern, options); // String
      }

    });

    return number;
  }
);
<commit_msg>added note<commit_after>define(["dojo/number", "dojo/_base/lang", "dojo/i18n"],
  function(dojoNumber, lang, i18n) {

    /*=====
     number.__FormatOptions = declare(null, {
     // pattern: String?
     //		override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
     //		with this string.  Default value is based on locale.  Overriding this property will defeat
     //		localization.  Literal characters in patterns are not supported.
     // type: String?
     //		choose a format type based on the locale from the following:
     //		decimal, scientific (not yet supported), percent, currency. decimal by default.
     // places: Number?
     //		fixed number of decimal places to show.  This overrides any
     //		information in the provided pattern.
     // round: Number?
     //		5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
     //		means do not round.
     // locale: String?
     //		override the locale used to determine formatting rules
     // fractional: Boolean?
     //		If false, show no decimal places, overriding places and pattern settings.
     // group: String?
     //   This string is used as group separator instead of the locale defined symbol, if given.
     });
     =====*/

    // summary:
    //   We take over the dojo/number functionality, to add the possibility in formatting to change the group
    //   symbol. It is possible to add a String "group" property to the FormatOptions
    var number = lang.delegate(dojoNumber, {

      format: function(/*Number*/ value, /*number.__FormatOptions?*/ options) {
        // summary:
        //		Format a Number as a String, using locale-specific settings
        // description:
        //		Create a string from a Number using a known localized pattern.
        //		Formatting patterns appropriate to the locale are chosen from the
        //		[Common Locale Data Repository](http://unicode.org/cldr) as well as the appropriate symbols and
        //		delimiters.
        //		If value is Infinity, -Infinity, or is not a valid JavaScript number, return null.
        // value:
        //		the number to be formatted

        options = lang.mixin({}, options || {});
        var locale = i18n.normalizeLocale(options.locale),
          bundle = i18n.getLocalization("dojo.cldr", "number", locale);
        options.customs = bundle || {};
        var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];
        if (options.group) { // no sense to pass through the empty string, since _applyPattern doesn't work with the empty string either
          options.customs.group = options.group;
        }
        if(isNaN(value) || Math.abs(value) == Infinity){ return null; } // null
        return this._applyPattern(value, pattern, options); // String
      }

    });

    return number;
  }
);
<|endoftext|>


<commit_before>/**
 * The Form Builder Component
 *
 * @module aui-form-builder
 * @submodule aui-form-builder-field-radio
 */

var L = A.Lang,

    CHECKED = 'checked',
    CHOICE = 'choice',
    CONTAINER = 'container',
    DISABLED = 'disabled',
    EMPTY_STR = '',
    FIELD = 'field',
    FORM_BUILDER_FIELD = 'form-builder-field',
    FORM_BUILDER_RADIO_FIELD = 'form-builder-radio-field',
    ID = 'id',
    INPUT = 'input',
    NAME = 'name',
    NODE = 'node',
    OPTIONS = 'options',
    PREDEFINED_VALUE = 'predefinedValue',
    RADIO = 'radio',
    SPACE = ' ',
    TEMPLATE_NODE = 'templateNode',

    getCN = A.getClassName,

    CSS_FIELD = getCN(FIELD),
    CSS_FIELD_CHOICE = getCN(FIELD, CHOICE),
    CSS_FIELD_RADIO = getCN(FIELD, RADIO),
    CSS_FORM_BUILDER_FIELD = getCN(FORM_BUILDER_FIELD),
    CSS_FORM_BUILDER_FIELD_NODE = getCN(FORM_BUILDER_FIELD, NODE),
    CSS_FORM_BUILDER_FIELD_OPTIONS_CONTAINER = getCN(FORM_BUILDER_FIELD, OPTIONS, CONTAINER),

    TPL_OPTIONS_CONTAINER = '

',
    TPL_RADIO =
        '
<input id="{id}" class="' + [CSS_FIELD, CSS_FIELD_CHOICE, CSS_FIELD_RADIO, CSS_FORM_BUILDER_FIELD_NODE].join(
            SPACE) +
        '" name="{name}" type="radio" value="{value}" {checked} {disabled} />{label}
';

/**
 * A base class for FormBuilderRadioField.
 *
 * @class A.FormBuilderRadioField
 * @extends A.FormBuilderMultipleChoiceField
 * @param config {Object} Object literal specifying widget configuration properties.
 * @constructor
 */
var FormBuilderRadioField = A.Component.create({

    /**
     * Static property provides a string to identify the class.
     *
     * @property NAME
     * @type String
     * @static
     */
    NAME: FORM_BUILDER_RADIO_FIELD,

    /**
     * Static property used to define the default attribute
     * configuration for the FormBuilderRadioField.
     *
     * @property ATTRS
     * @type Object
     * @static
     */
    ATTRS: {

        /**
         * The predefined value for the radio fields.
         *
         * @attribute predefinedValue
         */
        predefinedValue: {
            valueFn: '_valuePredefinedValueFn'
        },

        /**
         * TODO. Wanna help? Please send a Pull Request.
         *
         * @attribute template
         */
        template: {
            valueFn: function() {
                return TPL_RADIO;
            }
        }

    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @property CSS_PREFIX
     * @type String
     * @static
     */
    CSS_PREFIX: CSS_FORM_BUILDER_FIELD,

    /**
     * Static property used to define which component it extends.
     *
     * @property EXTENDS
     * @type Object
     * @static
     */
    EXTENDS: A.FormBuilderMultipleChoiceField,

    prototype: {

        /**
         * TODO. Wanna help? Please send a Pull Request.
         *
         * @method getHTML
         */
        getHTML: function() {
            return TPL_OPTIONS_CONTAINER;
        },

        /**
         * TODO. Wanna help? Please send a Pull Request.
         *
         * @method _uiSetDisabled
         * @param val
         * @protected
         */
        _uiSetDisabled: function(val) {
            var instance = this,
                templateNode = instance.get(TEMPLATE_NODE);

            templateNode.all(INPUT).each(function(input) {
                if (val) {
                    input.setAttribute(DISABLED, val);
                }
                else {
                    input.removeAttribute(DISABLED);
                }
            });
        },

        /**
         * TODO. Wanna help? Please send a Pull Request.
         *
         * @method _uiSetOptions
         * @param val
         * @protected
         */
        _uiSetOptions: function(val) {
            var instance = this,
                buffer = [],
                counter = 0,
                templateNode = instance.get(TEMPLATE_NODE);

            A.each(val, function(item, index, collection) {
                buffer.push(
                    L.sub(
                        TPL_RADIO, {
                            checked: item.value === instance.get(PREDEFINED_VALUE) ? 'checked="checked"' : EMPTY_STR,
                            disabled: instance.get(DISABLED) ? 'disabled="disabled"' : EMPTY_STR,
                            id: instance.get(ID) + counter++,
                            label: item.label,
                            name: instance.get(NAME),
                            value: item.value
                        }
                    )
                );
            });

            instance.optionNodes = A.NodeList.create(buffer.join(EMPTY_STR));

            templateNode.setContent(instance.optionNodes);

            instance._uiSetPredefinedValue(
                instance.get(PREDEFINED_VALUE)
            );
        },

        /**
         * TODO. Wanna help? Please send a Pull Request.
         *
         * @method _uiSetPredefinedValue
         * @param val
         * @protected
         */
        _uiSetPredefinedValue: function(val) {
            var instance = this,
                optionNodes = instance.optionNodes;

            if (!optionNodes) {
                return;
            }

            optionNodes.set(CHECKED, false);

            optionNodes.all('input[value="' + val + '"]').set(CHECKED, true);
        },

        /**
         * Returns the first option value if no predefined value is specified.
         *
         * @method _valuePredefinedValueFn
         * @protected
         */
        _valuePredefinedValueFn: function() {
            var instance = this,
                options = instance.get(OPTIONS),
                predefinedValue;

            if (options.length) {
                predefinedValue = options[0].value;
            }

            return predefinedValue;
        }

    }

});

A.FormBuilderRadioField = FormBuilderRadioField;

A.FormBuilder.types.radio = A.FormBuilderRadioField;
<commit_msg>AUI-1034 Predefined value is lost when radio option value is changed<commit_after>/**
 * The Form Builder Component
 *
 * @module aui-form-builder
 * @submodule aui-form-builder-field-radio
 */

var L = A.Lang,

    CHECKED = 'checked',
    CHOICE = 'choice',
    CONTAINER = 'container',
    DISABLED = 'disabled',
    EMPTY_STR = '',
    FIELD = 'field',
    FORM_BUILDER_FIELD = 'form-builder-field',
    FORM_BUILDER_RADIO_FIELD = 'form-builder-radio-field',
    ID = 'id',
    INPUT = 'input',
    NAME = 'name',
    NODE = 'node',
    OPTIONS = 'options',
    PREDEFINED_VALUE = 'predefinedValue',
    RADIO = 'radio',
    SPACE = ' ',
    TEMPLATE_NODE = 'templateNode',

    getCN = A.getClassName,

    CSS_FIELD = getCN(FIELD),
    CSS_FIELD_CHOICE = getCN(FIELD, CHOICE),
    CSS_FIELD_RADIO = getCN(FIELD, RADIO),
    CSS_FORM_BUILDER_FIELD = getCN(FORM_BUILDER_FIELD),
    CSS_FORM_BUILDER_FIELD_NODE = getCN(FORM_BUILDER_FIELD, NODE),
    CSS_FORM_BUILDER_FIELD_OPTIONS_CONTAINER = getCN(FORM_BUILDER_FIELD, OPTIONS, CONTAINER),

    TPL_OPTIONS_CONTAINER = '

',
    TPL_RADIO =
        '
<input id="{id}" class="' + [CSS_FIELD, CSS_FIELD_CHOICE, CSS_FIELD_RADIO, CSS_FORM_BUILDER_FIELD_NODE].join(
            SPACE) +
        '" name="{name}" type="radio" value="{value}" {checked} {disabled} />{label}
';

/**
 * A base class for FormBuilderRadioField.
 *
 * @class A.FormBuilderRadioField
 * @extends A.FormBuilderMultipleChoiceField
 * @param config {Object} Object literal specifying widget configuration properties.
 * @constructor
 */
var FormBuilderRadioField = A.Component.create({

    /**
     * Static property provides a string to identify the class.
     *
     * @property NAME
     * @type String
     * @static
     */
    NAME: FORM_BUILDER_RADIO_FIELD,

    /**
     * Static property used to define the default attribute
     * configuration for the FormBuilderRadioField.
     *
     * @property ATTRS
     * @type Object
     * @static
     */
    ATTRS: {

        /**
         * The predefined value for the radio fields.
         *
         * @attribute predefinedValue
         */
        predefinedValue: {
            valueFn: '_valuePredefinedValueFn'
        },

        /**
         * TODO. Wanna help? Please send a Pull Request.
         *
         * @attribute template
         */
        template: {
            valueFn: function() {
                return TPL_RADIO;
            }
        }

    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @property CSS_PREFIX
     * @type String
     * @static
     */
    CSS_PREFIX: CSS_FORM_BUILDER_FIELD,

    /**
     * Static property used to define which component it extends.
     *
     * @property EXTENDS
     * @type Object
     * @static
     */
    EXTENDS: A.FormBuilderMultipleChoiceField,

    prototype: {

        /**
         * TODO. Wanna help? Please send a Pull Request.
         *
         * @method getHTML
         */
        getHTML: function() {
            return TPL_OPTIONS_CONTAINER;
        },

        /**
         * TODO. Wanna help? Please send a Pull Request.
         *
         * @method _uiSetDisabled
         * @param val
         * @protected
         */
        _uiSetDisabled: function(val) {
            var instance = this,
                templateNode = instance.get(TEMPLATE_NODE);

            templateNode.all(INPUT).each(function(input) {
                if (val) {
                    input.setAttribute(DISABLED, val);
                }
                else {
                    input.removeAttribute(DISABLED);
                }
            });
        },

        /**
         * TODO. Wanna help? Please send a Pull Request.
         *
         * @method _uiSetOptions
         * @param val
         * @protected
         */
        _uiSetOptions: function(val) {
            var instance = this,
                buffer = [],
                counter = 0,
                hasPredefinedValue = false,
                predefinedValue = instance.get(PREDEFINED_VALUE),
                templateNode = instance.get(TEMPLATE_NODE);

            A.each(val, function(item, index, collection) {
                var index = A.Array.indexOf(predefinedValue, item.value);

                if (index != -1) {
                    hasPredefinedValue = true;
                }

                buffer.push(
                    L.sub(
                        TPL_RADIO, {
                            checked: (index != -1) ? 'checked="checked"' : EMPTY_STR,
                            disabled: instance.get(DISABLED) ? 'disabled="disabled"' : EMPTY_STR,
                            id: instance.get(ID) + counter++,
                            label: item.label,
                            name: instance.get(NAME),
                            value: item.value
                        }
                    )
                );
            });

            instance.optionNodes = A.NodeList.create(buffer.join(EMPTY_STR));

            templateNode.setContent(instance.optionNodes);

            if (!hasPredefinedValue) {
                instance.set(PREDEFINED_VALUE, instance._valuePredefinedValueFn());

                instance.get('builder').editField(instance);
            }
        },

        /**
         * TODO. Wanna help? Please send a Pull Request.
         *
         * @method _uiSetPredefinedValue
         * @param val
         * @protected
         */
        _uiSetPredefinedValue: function(val) {
            var instance = this,
                optionNodes = instance.optionNodes;

            if (!optionNodes) {
                return;
            }

            optionNodes.set(CHECKED, false);

            optionNodes.all('input[value="' + val + '"]').set(CHECKED, true);
        },

        /**
         * Returns the first option value if no predefined value is specified.
         *
         * @method _valuePredefinedValueFn
         * @protected
         */
        _valuePredefinedValueFn: function() {
            var instance = this,
                options = instance.get(OPTIONS),
                predefinedValue;

            if (options.length) {
                predefinedValue = options[0].value;
            }

            return predefinedValue;
        }

    }

});

A.FormBuilderRadioField = FormBuilderRadioField;

A.FormBuilder.types.radio = A.FormBuilderRadioField;
<|endoftext|>


<commit_before>/* global $, stringify, CodeMirror, document, io */

const $inputObjectId = $('#input-object-id');

const $indicatorObjectId = $('#indicator-object-id');
const $indicatorViewId = $('#indicator-view-id');

const $buttonSaveObject = $('#button-save-object');
const $buttonDelObject = $('#button-del-object');
const $buttonConfirmDelObject = $('#button-confirm-del-object');

const $inputViewId = $('#input-view-id');
const $inputViewFilter = $('#input-view-filter');

const $buttonSaveView = $('#button-save-view');
const $buttonDelView = $('#button-del-view');
const $buttonConfirmDelView = $('#button-confirm-del-view');

const $indicatorObjectSaved = $('#indicator-object-saved');
const $indicatorViewSaved = $('#indicator-view-saved');

const $objectRev = $('#object-rev');
const $objectRevServer = $('#object-rev-server');
const $objectRevEditor = $('#object-rev-editor');

const $objectConflictId = $('#object-conflict-id');
const $buttonSaveObjectForce = $('#button-save-object-force');
const $buttonReloadObject = $('#button-reload-object');

const $dialogConfirmConflict = $('#dialog-confirm-conflict');
const $dialogConfirmDelObject = $('#dialog-confirm-del-object');
const $dialogConfirmDelView = $('#dialog-confirm-del-view');

const $jsonlint = $('#jsonlint');

let objectIds = [];
let currentObjectId;
let currentViewId;

const cmMap = CodeMirror.fromTextArea(document.querySelector('#input-view-map'), {
    autoCloseBrackets: true,
    lineNumbers: true,
    mode: 'javascript',
    foldGutter: true,
    gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter']
});

const cmReduce = CodeMirror.fromTextArea(document.querySelector('#input-view-reduce'), {
    autoCloseBrackets: true,
    lineNumbers: true,
    mode: 'javascript',
    foldGutter: true,
    gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter']
});

const cmResult = CodeMirror.fromTextArea(document.querySelector('#input-view-result'), {
    autoCloseBrackets: true,
    lineNumbers: true,
    mode: 'javascript',
    readOnly: 'nocursor',
    foldGutter: true,
    gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter']
});

const cmObject = CodeMirror.fromTextArea(document.querySelector('#input-object'), {
    autoCloseBrackets: true,
    lineNumbers: true,
    mode: 'javascript',
    foldGutter: true,
    gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter']
});

$('a[aria-controls="views"][data-toggle="tab"]').on('shown.bs.tab', () => {
    cmMap.refresh();
    cmReduce.refresh();
    cmResult.refresh();
});

const socket = io.connect();

socket.on('objectIds', data => {
    objectIds = data;

    if ($inputObjectId.typeahead) {
        $inputObjectId.typeahead('destroy');
    }

    $inputObjectId.typeahead({
        source: objectIds.sort(),
        minLength: 0,
        items: 12,
        afterSelect: () => {
            getObject($inputObjectId.val());
        }
    });

    $inputObjectId.keyup(e => {
        const id = $inputObjectId.val();
        if (id !== currentObjectId) {
            $inputObjectId.css({color: 'grey'});
        }
        if (e.which === 13) {
            if (id !== currentObjectId || !$indicatorObjectSaved.is(':visible')) {
                getObject(id);
            }
        }
    });

    $inputObjectId.blur(() => {
        const id = $inputObjectId.val();
        if (currentObjectId !== id) {
            getObject(id);
        }
    });
});

socket.on('viewIds', viewIds => {
    if ($inputViewId.typeahead) {
        $inputViewId.typeahead('destroy');
    }

    $inputViewId.typeahead({
        source: viewIds.sort(),
        minLength: 0,
        items: 12,
        afterSelect: () => {
            getView($inputViewId.val());
        }});

    $inputViewId.keyup(e => {
        const id = $inputViewId.val();
        if (id !== currentViewId) {
            $inputViewId.css({color: 'grey'});
        }
        if (e.which === 13) {
            if (id !== currentViewId || !$indicatorViewSaved.is(':visible')) {
                getView(id);
            }
        }
    });

    $inputViewId.blur(() => {
        if (currentViewId !== $inputViewId.val()) {
            getView($inputViewId.val(), true);
        }
    });
});

socket.on('updateView', id => {
    if (id === currentViewId) {
        getView(id);
    }
});

function clearObject() {
    $objectRev.html('');
    cmObject.setValue('');
    $buttonDelObject.attr('disabled', true);
    $buttonSaveObject.attr('disabled', true);
    $indicatorObjectSaved.hide();
    jsonLint();
}

function clearView() {
    // $viewsRev.html('');
    cmMap.setValue('');
    cmReduce.setValue('');
    cmResult.setValue('');
    $inputViewFilter.val('');
    $buttonDelView.attr('disabled', true);
    $buttonSaveView.attr('disabled', true);
    $indicatorViewSaved.hide();
}

function getObject(id) {
    currentObjectId = id;
    $inputObjectId.css({color: 'black'});

    socket.emit('getObject', id, data => {
        if (data) {
            $objectRev.html(data._rev);
            cmObject.setValue(stringify(data));
            $buttonDelObject.removeAttr('disabled');
            $indicatorObjectSaved.show();
        } else {
            clearObject();
        }

        jsonLint();
    });
}

function getView(id) {
    currentViewId = id;

    $inputViewId.css({color: 'black'});

    socket.emit('getView', id, data => {
        console.log('getView', id, data);
        if (data.query) {
            cmMap.setValue(data.query.map || '');
            cmReduce.setValue(data.query.reduce || '');
            $inputViewFilter.val(data.query.filter || '#');
            // $viewsRev.html(data.rev);
            const obj = {};
            if (data.view.error) {
                obj.error = data.view.error;
                obj._id = id;
            } else {
                obj.result = data.view.result;
                obj.length = data.view.result.length;
                obj._id = id;
                obj._rev = data.view._rev;
            }

            cmResult.setValue(stringify(obj));
            $('.object-link').click(function () {
                console.log($(this).data('object'));
                const id = JSON.parse('"' + $(this).data('object') + '"');
                console.log(id);
                $inputObjectId.val(id);
                getObject(id);
                $('#tablist a[href="#tab-objects"]').tab('show');
            });
            $indicatorViewSaved.show();
            $buttonDelView.removeAttr('disabled');
            $buttonSaveView.removeAttr('disabled');
        } else {
            clearView();
            if (id) {
                $buttonSaveView.removeAttr('disabled');
            }
        }
    });
}

function jsonLint() {
    try {
        JSON.parse(cmObject.getValue());
        $jsonlint.html('✔');
        $buttonSaveObject.removeAttr('disabled');
    } catch (err) {
        $jsonlint.html('❌');
        $buttonSaveObject.attr('disabled', true);
    }
}

$buttonSaveObject.attr('disabled', true);
$buttonDelObject.attr('disabled', true);
$indicatorObjectSaved.hide();

$buttonSaveView.attr('disabled', true);
$buttonDelView.attr('disabled', true);
$indicatorViewSaved.hide();

cmObject.on('change', () => {
    $indicatorObjectSaved.hide();
    jsonLint();
});

$inputViewFilter.keyup(() => {
    $indicatorViewSaved.hide();
});

cmMap.on('change', () => {
    $indicatorViewSaved.hide();
});

cmReduce.on('change', () => {
    $indicatorViewSaved.hide();
});

$buttonSaveObject.click(() => {
    const data = JSON.parse(cmObject.getValue());
    data._rev = parseInt($objectRev.html(), 10);
    socket.emit('set', $inputObjectId.val(), data, res => {
        if (res === 'ok') {
            $indicatorObjectSaved.show();
            getObject($inputObjectId.val());
        } else if (res.startsWith('rev mismatch')) {
            const [, revServer] = res.match(/rev mismatch ([0-9]+)/);
            $objectRevServer.html(revServer);
            $objectRevEditor.html($objectRev.html());
            $objectConflictId.html($inputObjectId.val());
            $dialogConfirmConflict.modal('show');
        }
    });
});

$buttonSaveObjectForce.click(() => {
    const data = JSON.parse(cmObject.getValue());
    data._rev = null;
    socket.emit('set', $inputObjectId.val(), data, () => {
        $indicatorObjectSaved.show();
        getObject($inputObjectId.val());
    });
    $dialogConfirmConflict.modal('hide');
});

$buttonReloadObject.click(() => {
    getObject($inputObjectId.val());
    $dialogConfirmConflict.modal('hide');
});

$buttonDelObject.click(() => {
    $indicatorObjectId.html($inputObjectId.val());
    $dialogConfirmDelObject.modal('show');
});

$buttonConfirmDelObject.click(() => {
    socket.emit('del', $inputObjectId.val(), () => {
        $inputObjectId.val('');
        clearObject();
    });
    $dialogConfirmDelObject.modal('hide');
});

$buttonSaveView.click(() => {
    socket.emit('query', $inputViewId.val(), {
        map: cmMap.getValue(),
        reduce: cmReduce.getValue(),
        filter: $inputViewFilter.val()
    }, () => {
        $indicatorViewSaved.show();
    });
});

$buttonDelView.click(() => {
    $indicatorViewId.html($inputViewId.val());
    $dialogConfirmDelView.modal('show');
});

$buttonConfirmDelView.click(() => {
    socket.emit('query', $inputViewId.val(), '', () => {
        $inputViewId.val('');
        clearView();
    });
    $dialogConfirmDelView.modal('hide');
});

$('.panel-top').resizable({
    handleSelector: '.splitter-horizontal',
    resizeWidth: false
});

$('.panel-left').resizable({
    handleSelector: '.splitter-vertical',
    resizeHeight: false
});
<commit_msg>fix lint error<commit_after>/* global $, stringify, CodeMirror, document, io */

const $inputObjectId = $('#input-object-id');

const $indicatorObjectId = $('#indicator-object-id');
const $indicatorViewId = $('#indicator-view-id');

const $buttonSaveObject = $('#button-save-object');
const $buttonDelObject = $('#button-del-object');
const $buttonConfirmDelObject = $('#button-confirm-del-object');

const $inputViewId = $('#input-view-id');
const $inputViewFilter = $('#input-view-filter');

const $buttonSaveView = $('#button-save-view');
const $buttonDelView = $('#button-del-view');
const $buttonConfirmDelView = $('#button-confirm-del-view');

const $indicatorObjectSaved = $('#indicator-object-saved');
const $indicatorViewSaved = $('#indicator-view-saved');

const $objectRev = $('#object-rev');
const $objectRevServer = $('#object-rev-server');
const $objectRevEditor = $('#object-rev-editor');

const $objectConflictId = $('#object-conflict-id');
const $buttonSaveObjectForce = $('#button-save-object-force');
const $buttonReloadObject = $('#button-reload-object');

const $dialogConfirmConflict = $('#dialog-confirm-conflict');
const $dialogConfirmDelObject = $('#dialog-confirm-del-object');
const $dialogConfirmDelView = $('#dialog-confirm-del-view');

const $jsonlint = $('#jsonlint');

let objectIds = [];
let currentObjectId;
let currentViewId;

const cmMap = CodeMirror.fromTextArea(document.querySelector('#input-view-map'), {
    autoCloseBrackets: true,
    lineNumbers: true,
    mode: 'javascript',
    foldGutter: true,
    gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter']
});

const cmReduce = CodeMirror.fromTextArea(document.querySelector('#input-view-reduce'), {
    autoCloseBrackets: true,
    lineNumbers: true,
    mode: 'javascript',
    foldGutter: true,
    gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter']
});

const cmResult = CodeMirror.fromTextArea(document.querySelector('#input-view-result'), {
    autoCloseBrackets: true,
    lineNumbers: true,
    mode: 'javascript',
    readOnly: 'nocursor',
    foldGutter: true,
    gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter']
});

const cmObject = CodeMirror.fromTextArea(document.querySelector('#input-object'), {
    autoCloseBrackets: true,
    lineNumbers: true,
    mode: 'javascript',
    foldGutter: true,
    gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter']
});

$('a[aria-controls="views"][data-toggle="tab"]').on('shown.bs.tab', () => {
    cmMap.refresh();
    cmReduce.refresh();
    cmResult.refresh();
});

const socket = io.connect();

socket.on('objectIds', data => {
    objectIds = data;

    if ($inputObjectId.typeahead) {
        $inputObjectId.typeahead('destroy');
    }

    $inputObjectId.typeahead({
        source: objectIds.sort(),
        minLength: 0,
        items: 12,
        afterSelect: () => {
            getObject($inputObjectId.val());
        }
    });

    $inputObjectId.keyup(e => {
        const id = $inputObjectId.val();
        if (id !== currentObjectId) {
            $inputObjectId.css({color: 'grey'});
        }
        if (e.which === 13) {
            if (id !== currentObjectId || !$indicatorObjectSaved.is(':visible')) {
                getObject(id);
            }
        }
    });

    $inputObjectId.blur(() => {
        const id = $inputObjectId.val();
        if (currentObjectId !== id) {
            getObject(id);
        }
    });
});

socket.on('viewIds', viewIds => {
    if ($inputViewId.typeahead) {
        $inputViewId.typeahead('destroy');
    }

    $inputViewId.typeahead({
        source: viewIds.sort(),
        minLength: 0,
        items: 12,
        afterSelect: () => {
            getView($inputViewId.val());
        }});

    $inputViewId.keyup(e => {
        const id = $inputViewId.val();
        if (id !== currentViewId) {
            $inputViewId.css({color: 'grey'});
        }
        if (e.which === 13) {
            if (id !== currentViewId || !$indicatorViewSaved.is(':visible')) {
                getView(id);
            }
        }
    });

    $inputViewId.blur(() => {
        if (currentViewId !== $inputViewId.val()) {
            getView($inputViewId.val(), true);
        }
    });
});

socket.on('updateView', id => {
    if (id === currentViewId) {
        getView(id);
    }
});

function clearObject() {
    $objectRev.html('');
    cmObject.setValue('');
    $buttonDelObject.attr('disabled', true);
    $buttonSaveObject.attr('disabled', true);
    $indicatorObjectSaved.hide();
    jsonLint();
}

function clearView() {
    // $viewsRev.html('');
    cmMap.setValue('');
    cmReduce.setValue('');
    cmResult.setValue('');
    $inputViewFilter.val('');
    $buttonDelView.attr('disabled', true);
    $buttonSaveView.attr('disabled', true);
    $indicatorViewSaved.hide();
}

function getObject(id) {
    currentObjectId = id;
    $inputObjectId.css({color: 'black'});

    socket.emit('getObject', id, data => {
        if (data) {
            $objectRev.html(data._rev);
            cmObject.setValue(stringify(data));
            $buttonDelObject.removeAttr('disabled');
            $indicatorObjectSaved.show();
        } else {
            clearObject();
        }

        jsonLint();
    });
}

function getView(id) {
    currentViewId = id;

    $inputViewId.css({color: 'black'});

    socket.emit('getView', id, data => {
        console.log('getView', id, data);
        if (data.query) {
            cmMap.setValue(data.query.map || '');
            cmReduce.setValue(data.query.reduce || '');
            $inputViewFilter.val(data.query.filter || '#');
            // $viewsRev.html(data.rev);
            const obj = {};
            if (data.view.error) {
                obj.error = data.view.error;
                obj._id = id;
            } else {
                obj.result = data.view.result;
                obj.length = data.view.result.length;
                obj._id = id;
                obj._rev = data.view._rev;
            }

            cmResult.setValue(stringify(obj));
            $('.object-link').click(function () {
                console.log($(this).data('object'));
                const id = JSON.parse('"' + $(this).data('object') + '"');
                console.log(id);
                $inputObjectId.val(id);
                getObject(id);
                $('#tablist a[href="#tab-objects"]').tab('show');
            });
            $indicatorViewSaved.show();
            $buttonDelView.removeAttr('disabled');
            $buttonSaveView.removeAttr('disabled');
        } else {
            clearView();
            if (id) {
                $buttonSaveView.removeAttr('disabled');
            }
        }
    });
}

function jsonLint() {
    try {
        JSON.parse(cmObject.getValue());
        $jsonlint.html('✔');
        $buttonSaveObject.removeAttr('disabled');
    } catch (err) {
        $jsonlint.html('❌');
        $buttonSaveObject.attr('disabled', true);
    }
}

$buttonSaveObject.attr('disabled', true);
$buttonDelObject.attr('disabled', true);
$indicatorObjectSaved.hide();

$buttonSaveView.attr('disabled', true);
$buttonDelView.attr('disabled', true);
$indicatorViewSaved.hide();

cmObject.on('change', () => {
    $indicatorObjectSaved.hide();
    jsonLint();
});

$inputViewFilter.keyup(() => {
    $indicatorViewSaved.hide();
});

cmMap.on('change', () => {
    $indicatorViewSaved.hide();
});

cmReduce.on('change', () => {
    $indicatorViewSaved.hide();
});

$buttonSaveObject.click(() => {
    const data = JSON.parse(cmObject.getValue());
    data._rev = parseInt($objectRev.html(), 10);
    socket.emit('set', $inputObjectId.val(), data, res => {
        if (res === 'ok') {
            $indicatorObjectSaved.show();
            getObject($inputObjectId.val());
        } else if (res.startsWith('rev mismatch')) {
            const [, revServer] = res.match(/rev mismatch (\d+)/);
            $objectRevServer.html(revServer);
            $objectRevEditor.html($objectRev.html());
            $objectConflictId.html($inputObjectId.val());
            $dialogConfirmConflict.modal('show');
        }
    });
});

$buttonSaveObjectForce.click(() => {
    const data = JSON.parse(cmObject.getValue());
    data._rev = null;
    socket.emit('set', $inputObjectId.val(), data, () => {
        $indicatorObjectSaved.show();
        getObject($inputObjectId.val());
    });
    $dialogConfirmConflict.modal('hide');
});

$buttonReloadObject.click(() => {
    getObject($inputObjectId.val());
    $dialogConfirmConflict.modal('hide');
});

$buttonDelObject.click(() => {
    $indicatorObjectId.html($inputObjectId.val());
    $dialogConfirmDelObject.modal('show');
});

$buttonConfirmDelObject.click(() => {
    socket.emit('del', $inputObjectId.val(), () => {
        $inputObjectId.val('');
        clearObject();
    });
    $dialogConfirmDelObject.modal('hide');
});

$buttonSaveView.click(() => {
    socket.emit('query', $inputViewId.val(), {
        map: cmMap.getValue(),
        reduce: cmReduce.getValue(),
        filter: $inputViewFilter.val()
    }, () => {
        $indicatorViewSaved.show();
    });
});

$buttonDelView.click(() => {
    $indicatorViewId.html($inputViewId.val());
    $dialogConfirmDelView.modal('show');
});

$buttonConfirmDelView.click(() => {
    socket.emit('query', $inputViewId.val(), '', () => {
        $inputViewId.val('');
        clearView();
    });
    $dialogConfirmDelView.modal('hide');
});

$('.panel-top').resizable({
    handleSelector: '.splitter-horizontal',
    resizeWidth: false
});

$('.panel-left').resizable({
    handleSelector: '.splitter-vertical',
    resizeHeight: false
});
<|endoftext|>


<commit_before>const index = [];

let timer = null,
    precision = 10,
    lastTime = 0,
    startTime = 0,
    offsetTime = 0,
    playing = false;

function processTime () {
    lastTime = (performance.now() - startTime) + offsetTime;

    for (let i=0; i<index.length; i++) {
        const currentItem = index[i];
        if (currentItem.playing) {
            // Check if the event should end
            if (lastTime > currentItem.time + currentItem.duration) {
                currentItem.playing = false;
                postMessage({
                    id: currentItem.id,
                    type: "end"
                });
            }
        }
        else {
            // Check if the event should begin
            if (lastTime > currentItem.time && currentItem.time + currentItem.duration > lastTime) {
                currentItem.playing = true;
                postMessage({
                    id: currentItem.id,
                    type: "begin"
                });
            }
        }
    }

    if (playing) {
        timer = setTimeout(processTime, precision);
    }
    else {
        timer = null;
        offsetTime = lastTime;
        postMessage({
            type: "pause"
        });
    }
}

addEventListener("message", (message) => {
    switch (message.data.type) {
        case "play":
            playing = true;
            startTime = performance.now();
            timer = setTimeout(processTime, precision);
            postMessage({
                type: "play"
            });
            break;
        case "pause":
            playing = false;
            break;
        case "seek":
            offsetTime = lastTime = message.data.time;
            postMessage({
                type: "seek",
                time: offsetTime
            });
            break;
        case "time":
            postMessage({
                type: "time",
                time: lastTime
            });
            break;
        case "add":
            let newEvent = message.data;
            newEvent.playing = false;
            index.push(newEvent);
            break;
        case "remove":
            let result = index.filter((obj) => obj.id === message.data.id);
            if (result) this.index.splice(this.index.indexOf(result), 1);
            break;
    }
});<commit_msg>Fixed seek bug The seeked time was previously stored as a string instead of a number, resulting in incorrect addition when computing time.<commit_after>const index = [];

let timer = null,
    precision = 10,
    lastTime = 0,
    startTime = 0,
    offsetTime = 0,
    playing = false;

function processTime () {
    lastTime = (performance.now() - startTime) + offsetTime;

    for (let i=0; i<index.length; i++) {
        const currentItem = index[i];
        if (currentItem.playing) {
            // Check if the event should end
            if (lastTime > currentItem.time + currentItem.duration) {
                currentItem.playing = false;
                postMessage({
                    id: currentItem.id,
                    type: "end"
                });
            }
        }
        else {
            // Check if the event should begin
            if (lastTime > currentItem.time && currentItem.time + currentItem.duration > lastTime) {
                currentItem.playing = true;
                postMessage({
                    id: currentItem.id,
                    type: "begin"
                });
            }
        }
    }

    if (playing) {
        timer = setTimeout(processTime, precision);
    }
    else {
        timer = null;
        offsetTime = lastTime;
        postMessage({
            type: "pause"
        });
    }
}

addEventListener("message", (message) => {
    switch (message.data.type) {
        case "play":
            playing = true;
            startTime = performance.now();
            timer = setTimeout(processTime, precision);
            postMessage({
                type: "play"
            });
            break;
        case "pause":
            playing = false;
            break;
        case "seek":
            offsetTime = lastTime = parseFloat(message.data.time);
            postMessage({
                type: "seek",
                time: offsetTime
            });
            break;
        case "time":
            postMessage({
                type: "time",
                time: lastTime
            });
            break;
        case "add":
            let newEvent = message.data;
            newEvent.playing = false;
            index.push(newEvent);
            break;
        case "remove":
            let result = index.filter((obj) => obj.id === message.data.id);
            if (result) this.index.splice(this.index.indexOf(result), 1);
            break;
    }
});<|endoftext|>


<commit_before>const config = require('config');
const franc = require('franc');

// Generate a page access token for your page from the App Dashboard
const PAGE_ACCESS_TOKEN = (process.env.MESSENGER_PAGE_ACCESS_TOKEN) ?
(process.env.MESSENGER_PAGE_ACCESS_TOKEN) :
config.get('pageAccessToken');

let FBMessenger = require('fb-messenger');
let messenger = new FBMessenger(PAGE_ACCESS_TOKEN);

export const handler = (data) => {
    let senderID = data.sender.id;
    let pageID = data.recipient.id;
    let timeOfMessage = data.timestamp;
    let message = data.message;
    let userProfile = "";

    let readableMessage = message.text;
    let lang = franc(readableMessage, {blacklist: ['src', 'zlm'], minLength: 3});

    console.log("[receivedMessage] user (%d) page (%d) timestamp (%d) and message (%s)",
    senderID, pageID, timeOfMessage, JSON.stringify(message));

    messenger.getProfile(senderID, function (err, body) {
        userProfile = body;
    });

    if(lang == "eng") {
        messenger.sendTextMessage(senderID, 'English');

    } else if (lang == "ind") {
        messenger.sendTextMessage(senderID, 'Maaf ${userProfile.first_name}!, bahasa indonesia ku belum bagus');

    }
}

export default handler;
<commit_msg>Updating Reply<commit_after>const config = require('config');
const franc = require('franc');

// Generate a page access token for your page from the App Dashboard
const PAGE_ACCESS_TOKEN = (process.env.MESSENGER_PAGE_ACCESS_TOKEN) ?
(process.env.MESSENGER_PAGE_ACCESS_TOKEN) :
config.get('pageAccessToken');

let FBMessenger = require('fb-messenger');
let messenger = new FBMessenger(PAGE_ACCESS_TOKEN);

export const handler = (data) => {
    let senderID = data.sender.id;
    let pageID = data.recipient.id;
    let timeOfMessage = data.timestamp;
    let message = data.message;
    let userProfile = "";

    let readableMessage = message.text;
    let lang = franc(readableMessage, {blacklist: ['src', 'zlm'], minLength: 3});

    console.log("[receivedMessage] user (%d) page (%d) timestamp (%d) and message (%s)",
    senderID, pageID, timeOfMessage, JSON.stringify(message));

    messenger.getProfile(senderID, function (err, body) {
        userProfile = body;
    });

    if(lang == "eng") {
        messenger.sendTextMessage(senderID, 'English');

    } else if (lang == "ind") {
        let stringToSend = 'Maaf ${userProfile.first_name}, bahasa indonesia ku belum bagus';
        messenger.sendTextMessage(senderID, stringToSend);

    }
}

export default handler;
<|endoftext|>


<commit_before>var app = app || {};

//Todo Item View
//TodoView实例将和当个独立的todo记录相关联。Todo实例负责编辑、更新和销毁相关的todo项。

app.TodoView = Backbone.View.extend({

    tagName: 'li',

    template: _.template( $('#item-template').html() ),

    events: {
        'dbclick label': 'edit',
        'keypress .edit': 'updateOnEnter',
        'blur .edit': 'close'
    },

    initialize: function(){
        //监听Todo模型的change事件，todo更新时，应用程序会重新渲染试图
        //注意：Todo模型是通过AppView在arguments参数传递进来的，并且在this.model上自动可用
        this.listenTo(this.model, 'change', this.render);
    },

    render: function(){
        this.$el.html( this.template( this.model.toJSON() ) );
        this.$input = this.$('.edit');
        return this;
    },

    edit: function(){
        this.$el.addClass('editing');
        this.$input.focus();
    },

    close: function(){
        var value = this.$input.val().trim();

        if(value){
            this.model.save({title: value});
        }

        this.$el.removeClass('editing');
    },

    updateOnEnter: function(e){
        if( e.which === ENTER_KEY ){
            this.close();
        }
    }

});<commit_msg>开发 标记完成/删除todo项功能<commit_after>var app = app || {};

//Todo Item View
//TodoView实例将和当个独立的todo记录相关联。Todo实例负责编辑、更新和销毁相关的todo项。

app.TodoView = Backbone.View.extend({

    tagName: 'li',

    template: _.template( $('#item-template').html() ),

    events: {
        'click .toggle': 'toggleCompleted',
        'dbclick label': 'edit',
        'click .destroy': 'clear',
        'keypress .edit': 'updateOnEnter',
        'blur .edit': 'close'
    },

    initialize: function(){
        //监听Todo模型的change事件，todo更新时，应用程序会重新渲染试图
        //注意：Todo模型是通过AppView在arguments参数传递进来的，并且在this.model上自动可用
        this.listenTo(this.model, 'change', this.render);

        this.listenTo(this.model, 'destroy', this.remove);
        this.listenTo(this.model, 'visible', this.toggleVisible);
    },

    render: function(){
        this.$el.html( this.template( this.model.toJSON() ) );

        this.$el.toggleClass( 'completed', this.model.get('completed') );
        this.toggleVisible();

        this.$input = this.$('.edit');
        return this;
    },

    toggleVisible: function(){
        this.$el.toggleClass( 'hidden', this.isHidden() )
    },

    isHidden: function(){
        var isCompleted = this.model.get('completed');
        return (
            (!isCompleted && app.TodoFilter === 'completed')
            || (isCompleted && app.TodoFilter === 'active')
        );
    },

    toggleCompleted: function(){
        this.model.toggle();
    },

    edit: function(){
        this.$el.addClass('editing');
        this.$input.focus();
    },

    close: function(){
        var value = this.$input.val().trim();

        if(value){
            this.model.save({title: value});
        }else{
            this.clear();
        }

        this.$el.removeClass('editing');
    },

    updateOnEnter: function(e){
        if( e.which === ENTER_KEY ){
            this.close();
        }
    },

    clear: function(){
        this.model.destroy();
    },

});<|endoftext|>


<commit_before>define("ace/snippets/powershell",["require","exports","module"], function(require, exports, module) {
"use strict";

exports.snippetText =undefined;
exports.scope = "powershell";

});
<commit_msg>Update tmp/bower_components/ace-builds/src/snippets/powershell.js<commit_after><|endoftext|>


<commit_before>/*
Breadcrumbs compponent.
*/

(function() {
  Bootstrap.BsBreadcrumbsItem = Bootstrap.ItemView.extend({
    tagName: ['li'],
    classNameBindings: ["isActive:active"],
    template: Ember.Handlebars.compile('{{#unless view.isActive}}{{#if view.content.model}}{{#link-to view.content.route model.id}}{{view.content.name}}{{/link-to}}{{else}}{{#link-to view.content.route}}{{view.content.name}}{{/link-to}}{{/if}}{{else}}{{view.content.name}}{{/unless}}'),
    isActive: (function() {
      return this.get('content.active');
    }).property('content.active')
  });

  Bootstrap.BsBreadcrumbs = Bootstrap.ItemsView.extend(Bootstrap.WithRouter, {
    tagName: ['ol'],
    classNames: ['breadcrumb'],
    currentPathObserver: (function() {
      this.get('router');
      return this.send('updateCrumbsByRoute');
    }).observes('router.url').on('init'),
    content: [],
    itemViewClass: Bootstrap.BsBreadcrumbsItem,
    nameDictionary: void 0,
    dictionaryNamePrefix: 'breadcrumbs',
    actions: {
      currentPathDidChange: function() {
        return this.send('updateCrumbsByRoute');
      },
      updateCrumbsByRoute: function() {
        var routes,
          _this = this;
        this.get('content').clear();
        routes = this.get('container').lookup('router:main');
        routes.get('router.currentHandlerInfos').forEach(function(route, i, arr) {
          var crumb, displayName, name, routeName, _ref, _ref1, _ref2;
          name = route.name;
          if (name.indexOf('.index') !== -1 || name === 'application') {
            return;
          }
          if ((_ref = route.handler.breadcrumbs) != null ? _ref.hidden : void 0) {
            return;
          }
          routeName = route.handler.routeName;
          if ((_ref1 = route.handler.breadcrumbs) != null ? _ref1.name : void 0) {
            displayName = route.handler.breadcrumbs.name;
          } else if ((_ref2 = _this.get('nameDictionary')) != null ? _ref2["" + _this.dictionaryNamePrefix + "." + routeName] : void 0) {
            displayName = _this.get('nameDictionary')["" + _this.dictionaryNamePrefix + "." + routeName];
          } else {
            displayName = route.handler.routeName.split('.').pop();
            displayName = displayName[0].toUpperCase() + displayName.slice(1).toLowerCase();
          }
          crumb = Ember.Object.create({
            route: route.handler.routeName,
            name: displayName,
            model: null,
            icon: null,
          });
          if (_this.get('content').length === 0) {
            crumb.setProperties({
              icon: 'fa fa-home home-icon'
            });
          }
          if (route.isDynamic) {
            crumb.setProperties({
              model: route.handler.context,
              name: route.handler.context.get('name')
            });
          }
          return _this.get('content').pushObject(crumb);
        });
        return this.get('content.lastObject').set('active', true);
      }
    }
  });

  Ember.Handlebars.helper('bs-breadcrumbs', Bootstrap.BsBreadcrumbs);

}).call(this);
<commit_msg>Make sure breadcrumbs are updated<commit_after>/*
Breadcrumbs compponent.
*/

(function() {
  Bootstrap.BsBreadcrumbsItem = Bootstrap.ItemView.extend({
    tagName: ['li'],
    classNameBindings: ["isActive:active"],
    template: Ember.Handlebars.compile('{{#unless view.isActive}}{{#if view.content.model}}{{#link-to view.content.route model.id}}{{view.content.name}}{{/link-to}}{{else}}{{#link-to view.content.route}}{{view.content.name}}{{/link-to}}{{/if}}{{else}}{{view.content.name}}{{/unless}}'),
    isActive: (function() {
      return this.get('content.active');
    }).property('content.active')
  });

  Bootstrap.BsBreadcrumbs = Bootstrap.ItemsView.extend(Bootstrap.WithRouter, {
    tagName: ['ol'],
    classNames: ['breadcrumb'],
    currentPathObserver: (function() {
      this.get('router');
      return this.send('updateCrumbsByRoute');
    }).observes('router.url').on('init'),
    content: [],
    itemViewClass: Bootstrap.BsBreadcrumbsItem,
    nameDictionary: void 0,
    dictionaryNamePrefix: 'breadcrumbs',
    actions: {
      currentPathDidChange: function() {
        return this.send('updateCrumbsByRoute');
      },
      updateCrumbsByRoute: function() {
        var routes,
          _this = this;
        this.get('content').clear();
        routes = this.get('container').lookup('router:main');
        routes.get('router.currentHandlerInfos').forEach(function(route, i, arr) {
          var crumb, displayName, name, routeName, _ref, _ref1, _ref2;
          name = route.name;
          if (name.indexOf('.index') !== -1 || name === 'application') {
            return;
          }
          if ((_ref = route.handler.breadcrumbs) != null ? _ref.hidden : void 0) {
            return;
          }
          routeName = route.handler.routeName;
          if (route.context != undefined && route.context.id) {
            displayName = route.context.id;
          } else if ((_ref1 = route.handler.breadcrumbs) != null ? _ref1.name : void 0) {
            displayName = route.handler.breadcrumbs.name;
          } else if ((_ref2 = _this.get('nameDictionary')) != null ? _ref2["" + _this.dictionaryNamePrefix + "." + routeName] : void 0) {
            displayName = _this.get('nameDictionary')["" + _this.dictionaryNamePrefix + "." + routeName];
          } else {
            displayName = route.handler.routeName.split('.').pop();
            displayName = displayName[0].toUpperCase() + displayName.slice(1).toLowerCase();
          }
          crumb = Ember.Object.create({
            route: route.handler.routeName,
            name: displayName,
            model: null,
            icon: null,
          });
          if (_this.get('content').length === 0) {
            crumb.setProperties({
              icon: 'fa fa-home home-icon'
            });
          }
          if (route.isDynamic) {
            crumb.setProperties({
              model: route.handler.context,
              name: route.handler.context.get('name') || name
            });
          }
          return _this.get('content').pushObject(crumb);
        });
        return this.get('content.lastObject').set('active', true);
      }
    }
  });

  Ember.Handlebars.helper('bs-breadcrumbs', Bootstrap.BsBreadcrumbs);

}).call(this);
<|endoftext|>