<commit_before>import Ember from 'ember';
import layout from '../../templates/components/power-select-typeahead/trigger';

const { Component, isBlank, run, computed } = Ember;

export default Component.extend({
  layout,
  tagName: '',

  // CPs
  text: computed('select.selected', 'extra.labelPath', {
    get() {
      return this.getSelectedAsText();
    },
    set(_, v) {
      return v;
    }
  }),

  // Lifecycle hooks
  didReceiveAttrs() {
    this._super(...arguments);
    let oldSelect = this.get('oldSelect');
    let newSelect = this.set('oldSelect', this.get('select'));
    if (!oldSelect) {
      return;
    }
    /*
     * We need to update the input field with value of the selected option whenever we're closing
     * the select box. But we also close the select box when we're loading search results and when
     * we remove input text -- so protect against this
     */
    if (oldSelect.isOpen && !newSelect.isOpen && !newSelect.loading && newSelect.searchText) {
      let input = document.querySelector(`#ember-power-select-typeahead-input-${newSelect.uniqueId}`);
      let newText = this.getSelectedAsText();
      if (input.value !== newText) {
        input.value = newText;
      }
      this.set('text', newText);
    }

    if (newSelect.lastSearchedText !== oldSelect.lastSearchedText) {
      if (isBlank(newSelect.lastSearchedText)) {
        run.schedule('actions', null, newSelect.actions.close, null, true);
      } else {
        run.schedule('actions', null, newSelect.actions.open);
      }
    } else if (!isBlank(newSelect.lastSearchedText) && newSelect.options.length === 0 && newSelect.loading) {
      run.schedule('actions', null, newSelect.actions.close, null, true);
    } else if (oldSelect.loading && !newSelect.loading && newSelect.options.length > 0) {
      run.schedule('actions', null, newSelect.actions.open);
    }
  },

  // Actions
  actions: {
    stopPropagation(e) {
      e.stopPropagation();
    },

    handleKeydown(e) {
      let isLetter = e.keyCode >= 48 && e.keyCode <= 90 || e.keyCode === 32; // Keys 0-9, a-z or SPACE
      let isSpecialKeyWhileClosed = !isLetter && !this.get('select.isOpen') && [13, 27, 38, 40].indexOf(e.keyCode) > -1;
      if (isLetter || isSpecialKeyWhileClosed) {
        e.stopPropagation();
      }
    },

    handleInputLocal(e) {
      this.get('onInput')(e);
      this.set('text', e.target.value);
    }
  },

  // Methods
  getSelectedAsText() {
    let labelPath = this.get('extra.labelPath');
    if (labelPath) {
      return this.get(`select.selected.${labelPath}`);
    } else {
      return this.get('select.selected');
    }
  }
});
<commit_msg>Fix onkeydown action always bubbling<commit_after>import Ember from 'ember';
import layout from '../../templates/components/power-select-typeahead/trigger';

const { Component, isBlank, run, computed } = Ember;

export default Component.extend({
  layout,
  tagName: '',

  // CPs
  text: computed('select.selected', 'extra.labelPath', {
    get() {
      return this.getSelectedAsText();
    },
    set(_, v) {
      return v;
    }
  }),

  // Lifecycle hooks
  didReceiveAttrs() {
    this._super(...arguments);
    let oldSelect = this.get('oldSelect');
    let newSelect = this.set('oldSelect', this.get('select'));
    if (!oldSelect) {
      return;
    }
    /*
     * We need to update the input field with value of the selected option whenever we're closing
     * the select box. But we also close the select box when we're loading search results and when
     * we remove input text -- so protect against this
     */
    if (oldSelect.isOpen && !newSelect.isOpen && !newSelect.loading && newSelect.searchText) {
      let input = document.querySelector(`#ember-power-select-typeahead-input-${newSelect.uniqueId}`);
      let newText = this.getSelectedAsText();
      if (input.value !== newText) {
        input.value = newText;
      }
      this.set('text', newText);
    }

    if (newSelect.lastSearchedText !== oldSelect.lastSearchedText) {
      if (isBlank(newSelect.lastSearchedText)) {
        run.schedule('actions', null, newSelect.actions.close, null, true);
      } else {
        run.schedule('actions', null, newSelect.actions.open);
      }
    } else if (!isBlank(newSelect.lastSearchedText) && newSelect.options.length === 0 && newSelect.loading) {
      run.schedule('actions', null, newSelect.actions.close, null, true);
    } else if (oldSelect.loading && !newSelect.loading && newSelect.options.length > 0) {
      run.schedule('actions', null, newSelect.actions.open);
    }
  },

  // Actions
  actions: {
    stopPropagation(e) {
      e.stopPropagation();
    },

    handleKeydown(e) {
      let isLetter = e.keyCode >= 48 && e.keyCode <= 90 || e.keyCode === 32; // Keys 0-9, a-z or SPACE
      let isSpecialKeyWhileClosed = !isLetter && !this.get('select.isOpen') && [13, 27, 38, 40].indexOf(e.keyCode) > -1;
      if (isLetter || isSpecialKeyWhileClosed) {
        e.stopPropagation();
      }

      let onkeydown = this.get('onKeydown');
      if (onkeydown && onkeydown(e) === false) {
        return false;
      }
    },

    handleInputLocal(e) {
      this.get('onInput')(e);
      this.set('text', e.target.value);
    }
  },

  // Methods
  getSelectedAsText() {
    let labelPath = this.get('extra.labelPath');
    if (labelPath) {
      return this.get(`select.selected.${labelPath}`);
    } else {
      return this.get('select.selected');
    }
  }
});
<|endoftext|>


<commit_before>/*
 *  Handles inactvitiy timeout UI: a modal containing an iframe with the login screen,
 *  allowing users to re-login without leaving the page and losing their work.
 */
hqDefine('hqwebapp/js/inactivity', [
    'jquery',
    'underscore',
    'hqwebapp/js/assert_properties',
    'hqwebapp/js/initial_page_data',
], function (
    $,
    _,
    assertProperties,
    initialPageData
) {
    var log = function (message) {
        console.log("[" + (new Date()).toLocaleTimeString() + "] " + message);  // eslint-disable-line no-console
    };

    var calculateDelayAndWarning = function (expiryDate) {
        var millisLeft = 1000 * 60 * 10,
            response = {show_warning: false};

        // Figure out when the session is going to expire
        if (expiryDate) {
            expiryDate = new Date(expiryDate);
            millisLeft = expiryDate - new Date();
            log("expiry date is " + expiryDate.toLocaleTimeString() + ", so there are " + (millisLeft / 1000 / 60) + " minutes left in the session");

            // Prevent runaway polling if the page is loaded and secure sessions is then turned OFF, which
            // will result in the user never getting logged out and eventually a negative number of millisLeft.
            // If the session just "expired", it might be a timing issue, so keep polling, but back off as more
            // time passes.
            millisLeft = Math.abs(millisLeft);
        } else {
            log("expiry date unknown, trying pinging for it in " + (millisLeft / 1000 / 60) + " minutes");
        }

        if (millisLeft < 30 * 1000) {
            // Last 30 seconds, ping every 3 seconds
            response.show_warning = true;
            response.delay = 3000;
            log("show warning and poll again in 3 sec");
        } else if (millisLeft < 2 * 60 * 1000) {
            // Last 2 minutes, ping every ten seconds
            response.show_warning = true;
            response.delay = 10 * 1000;
            log("show warning and poll again in 10 sec");
        } else {
            // We have time, ping when 2 minutes from expiring
            response.delay = millisLeft - 2 * 60 * 1000;
            log("poll again in " + (millisLeft - 2 * 60 * 1000) / 1000 / 60 + " minutes");
        }

        assertProperties.assertRequired(response, ['delay', 'show_warning']);
        return response;
    };

    $(function () {
        var $modal = $("#inactivityModal"),     // won't be present on app preview or pages without a domain
            $warningModal = $("#inactivityWarningModal"),
            $newVersionModal = $('#newAppVersionModal');

        // Avoid popping up the warning modal when the user is actively doing something with the keyboard or mouse.
        // The keyboardOrMouseActive flag is turned on whenever a keypress or mousemove is detected, then turned
        // off when there's a 0.5-second break. This is controlled by the kepress/mousemove handlers farther down.
        // The shouldShowWarning flag is active if the user's session is 2 minutes from expiring, but keyboard or
        // mouse activity is preventing us from actually showing it. It'll be shown at the next 0.5-sec break.
        var keyboardOrMouseActive = false,
            shouldShowWarning = false,
            sessionExpiry = initialPageData.get('session_expiry');

        log("Page loaded, session expires at " + sessionExpiry);
        if (!$modal.length) {
            log("Could not find modal, returning");
            return;
        }
        if ($newVersionModal.length) {
            $('#refreshApp').click(function () {
                history.pushState("", document.title, window.location.pathname + window.location.search);
                window.location.reload();
            });
        }
        /**
          * Determine when to poll next. Poll more frequently as expiration approaches, to
          * increase the chance the modal pops up before the user takes an action and gets rejected.
          */
        var getDelayAndWarnIfNeeded = function (expiryDate) {
            var response = calculateDelayAndWarning(expiryDate);
            if (response.show_warning) {
                showWarningModal();
            }

            return response.delay;
        };

        var showWarningModal = function () {
            if (keyboardOrMouseActive) {
                // Can't show the popup because user is working, but set a flag
                // that will be checked when they stop typing/mousemoving.
                shouldShowWarning = true;
            } else {
                shouldShowWarning = false;
                // Close the New version modal before showing warning modal
                if (isModalOpen($newVersionModal)) {
                    $newVersionModal.modal('hide');
                }
                $warningModal.modal('show');
            }
        };

        var hideWarningModal = function (showLogin) {
            $warningModal.modal('hide');
            if (showLogin) {
                $modal.modal({backdrop: 'static', keyboard: false});
            }
            // This flag should already have been turned off when the warning modal was shown,
            // but just in case, make sure it's really off. Wait until the modal is fully hidden
            // to avoid issues with code trying to re-show this popup just as we're closing it.
            shouldShowWarning = false;
        };

        var isModalOpen = function (element) {
            // https://stackoverflow.com/questions/19506672/how-to-check-if-bootstrap-modal-is-open-so-i-can-use-jquery-validate
            return (element.data('bs.modal') || {}).isShown;
        };

        var showPageRefreshModal = function () {
            if (!isModalOpen($modal) && !isModalOpen($warningModal)) {
                $newVersionModal.modal('show');
            }
        };

        var pollToShowModal = function () {
            log("polling HQ's ping_login to decide about showing login modal");
            var selectedAppId = '';
            try {
                var urlParams = JSON.parse(decodeURIComponent(window.location.hash.substr(1)));
                selectedAppId = urlParams.appId;
            } catch (error) {
                console.log(error);
            }
            var domain = initialPageData.get('domain');
            $.ajax({
                url: initialPageData.reverse('ping_login'),
                type: 'GET',
                data: {
                    selected_app_id: selectedAppId,
                    domain: domain,
                },
                success: function (data) {
                    if (!data.success) {
                        _.each($(".select2-hidden-accessible"), function (el) {
                            $(el).select2('close');
                        });
                        // Close the New version modal before showing login iframe
                        $newVersionModal.modal('hide');
                        log("ping_login failed, showing login modal");
                        var $body = $modal.find(".modal-body");
                        var src = initialPageData.reverse('iframe_domain_login');
                        src += "?next=" + initialPageData.reverse('domain_login_new_window');
                        src += "&username=" + initialPageData.get('secure_timeout_username');
                        $modal.on('shown.bs.modal', function () {
                            var content = _.template('<iframe src="<%- src %>" height="<%- height %>" width="<%- width %>" style="border: none;">')({
                                src: src,
                                width: $body.width(),
                                height: $body.height() - 10,
                            });
                            $body.html(content);
                            $body.find("iframe").on("load", pollToHideModal);
                        });
                        $body.html('

');
                        hideWarningModal(true);
                    } else {
                        log("ping_login succeeded, time to re-calculate when the next poll should be, data was " + JSON.stringify(data));
                        _.delay(pollToShowModal, getDelayAndWarnIfNeeded(data.session_expiry));
                    }
                    if (
                        data.success &&
                        data.new_app_version_available
                    ) {
                        showPageRefreshModal();
                    }
                },
            });
        };

        var pollToHideModal = function (e) {
            var $button = $(e.currentTarget);
            $button.disableButton();
            $.ajax({
                url: initialPageData.reverse('ping_login'),
                type: 'GET',
                success: function (data) {
                    $button.enableButton();
                    var error = "";
                    if (data.success) {
                        if (data.username !== initialPageData.get('secure_timeout_username')) {
                            error = gettext(_.template("Please log in as <%- username %>"))({
                                username: initialPageData.get('secure_timeout_username'),
                            });
                        }
                    } else {
                        error = gettext("Could not authenticate, please log in and try again");
                    }

                    if (error) {
                        $button.removeClass("btn-default").addClass("btn-danger");
                        $button.text(error);
                    } else {
                        // Keeps the input value in the outer window in sync with newest token generated in
                        // iframe_close_window after session timeout, avoiding csrf error.
                        var iframe = $('iframe').get(0).contentWindow.document;
                        var outerCSRFInput = $('#csrfTokenContainer');
                        var iframeInputValue;
                        try {
                            iframeInputValue = iframe.getElementsByTagName('input')[0].value;
                            outerCSRFInput.val(iframeInputValue);
                        } catch (err) {
                            $button.removeClass("btn-default").addClass("btn-danger");
                            error = gettext("There was a problem, please refresh and try again");
                            $button.text(error);
                            return null;
                        }
                        $modal.modal('hide');
                        $button.text(gettext("Done"));
                        _.delay(pollToShowModal, getDelayAndWarnIfNeeded(data.session_expiry));
                    }
                },
            });
        };

        var extendSession = function ($button) {
            log("extending session");
            if ($button) {
                $button.disableButton();
            }
            shouldShowWarning = false;
            $.ajax({
                url: initialPageData.reverse('ping_session'),  // View that will trigger session activity
                type: 'GET',
                success: function () {
                    if ($button) {
                        $button.enableButton();
                    }
                    log("session successfully extended, hiding warning popup if it's open");
                    hideWarningModal();
                },
            });
        };

        $modal.find(".modal-footer .dismiss-button").click(pollToHideModal);
        $warningModal.find(".modal-footer .dismiss-button").click(function (e) {
            extendSession($(e.currentTarget));
        });
        $warningModal.on('shown.bs.modal', function () {
            $warningModal.find(".btn-primary").focus();
        });

        // Keep track of when user is actively typing
        $("body").on("keypress mousemove", _.throttle(function () {
            keyboardOrMouseActive = true;
        }, 100, {trailing: false}));
        $("body").on("keypress mousemove", _.debounce(function () {
            keyboardOrMouseActive = false;
            if (shouldShowWarning) {
                showWarningModal();
            }
        }, 500));

        // Send no-op request to server to extend session when there's client-side user activity on this page.
        // _.throttle will prevent this from happening too often.
        var keepAliveTimeout = 5 * 60 * 1000;
        log("page loaded, will send a keep-alive request to server every click/keypress, at most once every " + (keepAliveTimeout / 1000 / 60) + " minutes");
        $("body").on("keypress click", _.throttle(function () {
            extendSession();
        }, keepAliveTimeout));

        // Start polling
        _.delay(pollToShowModal, getDelayAndWarnIfNeeded(sessionExpiry));

        /**
         * This function is for subscribing to changes in localStorage in order
         * to check if a value for the 'ssoMessage' was updated. We use this
         * to keep track of the SSO login status in an external window, as
         * we cannot load external websites for Identity Providers in an
         * iframe in order to complete a full SSO sign in.
         */
        var checkIfSsoMessageReceivedFromExternalTab = function (event) {
            if (event.originalEvent.key !== 'ssoInactivityMessage') {
                // ignore other messages
                return;
            }
            var message = JSON.parse(event.originalEvent.newValue);
            if (!message) {
                return;
            }

            if (message.isLoggedIn) {
                log("session successfully extended via Single Sign On in external tab");
                hideWarningModal();
                $modal.modal('hide');
                localStorage.removeItem('ssoInactivityMessage');
            }
        };

        window.addEventListener('storage', checkIfSsoMessageReceivedFromExternalTab);
    });

    return {
        calculateDelayAndWarning: calculateDelayAndWarning,
    };
});
<commit_msg>use document.location instead of pushstate<commit_after>/*
 *  Handles inactvitiy timeout UI: a modal containing an iframe with the login screen,
 *  allowing users to re-login without leaving the page and losing their work.
 */
hqDefine('hqwebapp/js/inactivity', [
    'jquery',
    'underscore',
    'hqwebapp/js/assert_properties',
    'hqwebapp/js/initial_page_data',
], function (
    $,
    _,
    assertProperties,
    initialPageData
) {
    var log = function (message) {
        console.log("[" + (new Date()).toLocaleTimeString() + "] " + message);  // eslint-disable-line no-console
    };

    var calculateDelayAndWarning = function (expiryDate) {
        var millisLeft = 1000 * 60 * 10,
            response = {show_warning: false};

        // Figure out when the session is going to expire
        if (expiryDate) {
            expiryDate = new Date(expiryDate);
            millisLeft = expiryDate - new Date();
            log("expiry date is " + expiryDate.toLocaleTimeString() + ", so there are " + (millisLeft / 1000 / 60) + " minutes left in the session");

            // Prevent runaway polling if the page is loaded and secure sessions is then turned OFF, which
            // will result in the user never getting logged out and eventually a negative number of millisLeft.
            // If the session just "expired", it might be a timing issue, so keep polling, but back off as more
            // time passes.
            millisLeft = Math.abs(millisLeft);
        } else {
            log("expiry date unknown, trying pinging for it in " + (millisLeft / 1000 / 60) + " minutes");
        }

        if (millisLeft < 30 * 1000) {
            // Last 30 seconds, ping every 3 seconds
            response.show_warning = true;
            response.delay = 3000;
            log("show warning and poll again in 3 sec");
        } else if (millisLeft < 2 * 60 * 1000) {
            // Last 2 minutes, ping every ten seconds
            response.show_warning = true;
            response.delay = 10 * 1000;
            log("show warning and poll again in 10 sec");
        } else {
            // We have time, ping when 2 minutes from expiring
            response.delay = millisLeft - 2 * 60 * 1000;
            log("poll again in " + (millisLeft - 2 * 60 * 1000) / 1000 / 60 + " minutes");
        }

        assertProperties.assertRequired(response, ['delay', 'show_warning']);
        return response;
    };

    $(function () {
        var $modal = $("#inactivityModal"),     // won't be present on app preview or pages without a domain
            $warningModal = $("#inactivityWarningModal"),
            $newVersionModal = $('#newAppVersionModal');

        // Avoid popping up the warning modal when the user is actively doing something with the keyboard or mouse.
        // The keyboardOrMouseActive flag is turned on whenever a keypress or mousemove is detected, then turned
        // off when there's a 0.5-second break. This is controlled by the kepress/mousemove handlers farther down.
        // The shouldShowWarning flag is active if the user's session is 2 minutes from expiring, but keyboard or
        // mouse activity is preventing us from actually showing it. It'll be shown at the next 0.5-sec break.
        var keyboardOrMouseActive = false,
            shouldShowWarning = false,
            sessionExpiry = initialPageData.get('session_expiry');

        log("Page loaded, session expires at " + sessionExpiry);
        if (!$modal.length) {
            log("Could not find modal, returning");
            return;
        }
        if ($newVersionModal.length) {
            $('#refreshApp').click(function () {
                document.location = document.location.origin + document.location.pathname;
            });
        }
        /**
          * Determine when to poll next. Poll more frequently as expiration approaches, to
          * increase the chance the modal pops up before the user takes an action and gets rejected.
          */
        var getDelayAndWarnIfNeeded = function (expiryDate) {
            var response = calculateDelayAndWarning(expiryDate);
            if (response.show_warning) {
                showWarningModal();
            }

            return response.delay;
        };

        var showWarningModal = function () {
            if (keyboardOrMouseActive) {
                // Can't show the popup because user is working, but set a flag
                // that will be checked when they stop typing/mousemoving.
                shouldShowWarning = true;
            } else {
                shouldShowWarning = false;
                // Close the New version modal before showing warning modal
                if (isModalOpen($newVersionModal)) {
                    $newVersionModal.modal('hide');
                }
                $warningModal.modal('show');
            }
        };

        var hideWarningModal = function (showLogin) {
            $warningModal.modal('hide');
            if (showLogin) {
                $modal.modal({backdrop: 'static', keyboard: false});
            }
            // This flag should already have been turned off when the warning modal was shown,
            // but just in case, make sure it's really off. Wait until the modal is fully hidden
            // to avoid issues with code trying to re-show this popup just as we're closing it.
            shouldShowWarning = false;
        };

        var isModalOpen = function (element) {
            // https://stackoverflow.com/questions/19506672/how-to-check-if-bootstrap-modal-is-open-so-i-can-use-jquery-validate
            return (element.data('bs.modal') || {}).isShown;
        };

        var showPageRefreshModal = function () {
            if (!isModalOpen($modal) && !isModalOpen($warningModal)) {
                $newVersionModal.modal('show');
            }
        };

        var pollToShowModal = function () {
            log("polling HQ's ping_login to decide about showing login modal");
            var selectedAppId = '';
            try {
                var urlParams = JSON.parse(decodeURIComponent(window.location.hash.substr(1)));
                selectedAppId = urlParams.appId;
            } catch (error) {
                console.log(error);
            }
            var domain = initialPageData.get('domain');
            $.ajax({
                url: initialPageData.reverse('ping_login'),
                type: 'GET',
                data: {
                    selected_app_id: selectedAppId,
                    domain: domain,
                },
                success: function (data) {
                    if (!data.success) {
                        _.each($(".select2-hidden-accessible"), function (el) {
                            $(el).select2('close');
                        });
                        // Close the New version modal before showing login iframe
                        $newVersionModal.modal('hide');
                        log("ping_login failed, showing login modal");
                        var $body = $modal.find(".modal-body");
                        var src = initialPageData.reverse('iframe_domain_login');
                        src += "?next=" + initialPageData.reverse('domain_login_new_window');
                        src += "&username=" + initialPageData.get('secure_timeout_username');
                        $modal.on('shown.bs.modal', function () {
                            var content = _.template('<iframe src="<%- src %>" height="<%- height %>" width="<%- width %>" style="border: none;">')({
                                src: src,
                                width: $body.width(),
                                height: $body.height() - 10,
                            });
                            $body.html(content);
                            $body.find("iframe").on("load", pollToHideModal);
                        });
                        $body.html('

');
                        hideWarningModal(true);
                    } else {
                        log("ping_login succeeded, time to re-calculate when the next poll should be, data was " + JSON.stringify(data));
                        _.delay(pollToShowModal, getDelayAndWarnIfNeeded(data.session_expiry));
                    }
                    if (
                        data.success &&
                        data.new_app_version_available
                    ) {
                        showPageRefreshModal();
                    }
                },
            });
        };

        var pollToHideModal = function (e) {
            var $button = $(e.currentTarget);
            $button.disableButton();
            $.ajax({
                url: initialPageData.reverse('ping_login'),
                type: 'GET',
                success: function (data) {
                    $button.enableButton();
                    var error = "";
                    if (data.success) {
                        if (data.username !== initialPageData.get('secure_timeout_username')) {
                            error = gettext(_.template("Please log in as <%- username %>"))({
                                username: initialPageData.get('secure_timeout_username'),
                            });
                        }
                    } else {
                        error = gettext("Could not authenticate, please log in and try again");
                    }

                    if (error) {
                        $button.removeClass("btn-default").addClass("btn-danger");
                        $button.text(error);
                    } else {
                        // Keeps the input value in the outer window in sync with newest token generated in
                        // iframe_close_window after session timeout, avoiding csrf error.
                        var iframe = $('iframe').get(0).contentWindow.document;
                        var outerCSRFInput = $('#csrfTokenContainer');
                        var iframeInputValue;
                        try {
                            iframeInputValue = iframe.getElementsByTagName('input')[0].value;
                            outerCSRFInput.val(iframeInputValue);
                        } catch (err) {
                            $button.removeClass("btn-default").addClass("btn-danger");
                            error = gettext("There was a problem, please refresh and try again");
                            $button.text(error);
                            return null;
                        }
                        $modal.modal('hide');
                        $button.text(gettext("Done"));
                        _.delay(pollToShowModal, getDelayAndWarnIfNeeded(data.session_expiry));
                    }
                },
            });
        };

        var extendSession = function ($button) {
            log("extending session");
            if ($button) {
                $button.disableButton();
            }
            shouldShowWarning = false;
            $.ajax({
                url: initialPageData.reverse('ping_session'),  // View that will trigger session activity
                type: 'GET',
                success: function () {
                    if ($button) {
                        $button.enableButton();
                    }
                    log("session successfully extended, hiding warning popup if it's open");
                    hideWarningModal();
                },
            });
        };

        $modal.find(".modal-footer .dismiss-button").click(pollToHideModal);
        $warningModal.find(".modal-footer .dismiss-button").click(function (e) {
            extendSession($(e.currentTarget));
        });
        $warningModal.on('shown.bs.modal', function () {
            $warningModal.find(".btn-primary").focus();
        });

        // Keep track of when user is actively typing
        $("body").on("keypress mousemove", _.throttle(function () {
            keyboardOrMouseActive = true;
        }, 100, {trailing: false}));
        $("body").on("keypress mousemove", _.debounce(function () {
            keyboardOrMouseActive = false;
            if (shouldShowWarning) {
                showWarningModal();
            }
        }, 500));

        // Send no-op request to server to extend session when there's client-side user activity on this page.
        // _.throttle will prevent this from happening too often.
        var keepAliveTimeout = 5 * 60 * 1000;
        log("page loaded, will send a keep-alive request to server every click/keypress, at most once every " + (keepAliveTimeout / 1000 / 60) + " minutes");
        $("body").on("keypress click", _.throttle(function () {
            extendSession();
        }, keepAliveTimeout));

        // Start polling
        _.delay(pollToShowModal, getDelayAndWarnIfNeeded(sessionExpiry));

        /**
         * This function is for subscribing to changes in localStorage in order
         * to check if a value for the 'ssoMessage' was updated. We use this
         * to keep track of the SSO login status in an external window, as
         * we cannot load external websites for Identity Providers in an
         * iframe in order to complete a full SSO sign in.
         */
        var checkIfSsoMessageReceivedFromExternalTab = function (event) {
            if (event.originalEvent.key !== 'ssoInactivityMessage') {
                // ignore other messages
                return;
            }
            var message = JSON.parse(event.originalEvent.newValue);
            if (!message) {
                return;
            }

            if (message.isLoggedIn) {
                log("session successfully extended via Single Sign On in external tab");
                hideWarningModal();
                $modal.modal('hide');
                localStorage.removeItem('ssoInactivityMessage');
            }
        };

        window.addEventListener('storage', checkIfSsoMessageReceivedFromExternalTab);
    });

    return {
        calculateDelayAndWarning: calculateDelayAndWarning,
    };
});
<|endoftext|>


<commit_before>import { connect } from 'react-redux';
import Connections from '../components/Connections.jsx';
import { removeConnection } from '../actions/index.js';
import { addRoom, changeCurrentRoom } from '../../conversations/actions/index.js'; // separate concerns somehow?
import request from 'then-request';

const mapStateToProps = (state) => (
  {
    connections: state.connections,
    selfId: state.profile.id,
    rooms: state.rooms,
  }
);

const mapDispatchToProps = (dispatch) => (
  {
    onNewConvo: (selfId, connection, currentRooms) => {
      request('POST', '/api/relationships', {
        json: {
          selfId,
          connectionId: connection.id,
        },
      })
      .done(data => {
        if (data.statusCode === 201) {
          const returnedRoom = JSON.parse(data.body);
          console.log(returnedRoom);
          console.log(currentRooms);
          const dupIndex = currentRooms.reduce((cum, currentRoom, i) =>
            (currentRoom.id === returnedRoom.id) ? i : cum, -1);

          console.log(dupIndex);
          (dupIndex === -1) ?
            dispatch(addRoom(returnedRoom, connection)) :
            dispatch(changeCurrentRoom(dupIndex));
        } else {
          // TODO: handle error
        }
      });
    },

    onRemoveClick: (selfId, connectionId) => {
      request('PUT', '/api/relationships', {
        json: {
          oldType: 'connection',
          selfId,
          connectionId,
        },
      })
      .done(data => {
        if (data.statusCode === 200) {
          dispatch(removeConnection(connectionId));
        } else {
          // TODO: handle error
        }
      });
    },
  }
);

export default connect(mapStateToProps, mapDispatchToProps)(Connections);
<commit_msg>Change endpoint for starting a room<commit_after>import { connect } from 'react-redux';
import Connections from '../components/Connections.jsx';
import { removeConnection } from '../actions/index.js';
import { addRoom, changeCurrentRoom } from '../../conversations/actions/index.js'; // separate concerns somehow?
import request from 'then-request';

const mapStateToProps = (state) => (
  {
    connections: state.connections,
    selfId: state.profile.id,
    rooms: state.rooms,
  }
);

const mapDispatchToProps = (dispatch) => (
  {
    onNewConvo: (selfId, connection, currentRooms) => {
      request('POST', '/api/rooms', {
        json: {
          selfId,
          connectionId: connection.id,
        },
      })
      .done(data => {
        if (data.statusCode === 201) {
          const returnedRoom = JSON.parse(data.body);
          console.log(returnedRoom);
          console.log(currentRooms);
          const dupIndex = currentRooms.reduce((cum, currentRoom, i) =>
            (currentRoom.id === returnedRoom.id) ? i : cum, -1);

          console.log(dupIndex);
          (dupIndex === -1) ?
            dispatch(addRoom(returnedRoom, connection)) :
            dispatch(changeCurrentRoom(dupIndex));
        } else {
          // TODO: handle error
        }
      });
    },

    onRemoveClick: (selfId, connectionId) => {
      request('PUT', '/api/relationships', {
        json: {
          oldType: 'connection',
          selfId,
          connectionId,
        },
      })
      .done(data => {
        if (data.statusCode === 200) {
          dispatch(removeConnection(connectionId));
        } else {
          // TODO: handle error
        }
      });
    },
  }
);

export default connect(mapStateToProps, mapDispatchToProps)(Connections);
<|endoftext|>


<commit_before>//= require "../chrome/storage"

var libraries = [
    {
        "url": "http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js",
        "label": "jQuery latest",
        "group": "jQuery"
    },
    {
        "url": "http://code.jquery.com/jquery-git.js",
        "label": "jQuery WIP (via git)",
        "group": "jQuery"
    },
    {
        "url": "http://code.jquery.com/jquery-1.8.1.min.js",
        "label": "jQuery 1.8.1",
        "group": "jQuery"
    },
    {
        "url": "http://code.jquery.com/jquery-1.7.2.min.js",
        "label": "jQuery 1.7.2",
        "group": "jQuery"
    },
    {
        "url": [
            "http://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/base/jquery-ui.css",
            "http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js",
            "http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"
        ],
        "label": "jQuery UI latest",
        "group": "jQuery UI"
    },
    {
        "url": [
            "http://code.jquery.com/ui/jquery-ui-git.css",
            "http://code.jquery.com/jquery-git.js",
            "http://code.jquery.com/ui/jquery-ui-git.js"
        ],
        "label": "jQuery UI WIP (via git)",
        "group": "jQuery UI"
    },
    {
        "url": [
            "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/themes/base/jquery-ui.css",
            "http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js",
            "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js"
        ],
        "label": "jQuery UI 1.8.23",
        "group": "jQuery UI"
    },
    {
        "url": [
            "http://code.jquery.com/mobile/latest/jquery.mobile.css",
            "http://code.jquery.com/jquery-1.6.4.min.js",
            "http://code.jquery.com/mobile/latest/jquery.mobile.js"
        ],
        "label": "jQuery Mobile Latest",
        "group": "jQuery Mobile"
    },
    {
        "url": [
            "http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css",
            "http://code.jquery.com/jquery-1.6.4.min.js",
            "http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.js"
        ],
        "label": "jQuery Mobile 1.1.0",
        "group": "jQuery Mobile"
    },
    {
        "url": [
            "http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css",
            "http://code.jquery.com/jquery-1.6.4.min.js",
            "http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.1.min.js"
        ],
        "label": "jQuery Mobile 1.0.1",
        "group": "jQuery Mobile"
    },
    {
        "url": [
            "http://code.jquery.com/jquery.min.js",
            "http://twitter.github.com/bootstrap/assets/css/bootstrap.css",
            "http://twitter.github.com/bootstrap/assets/css/bootstrap-responsive.css",
            "http://twitter.github.com/bootstrap/assets/js/bootstrap.js"
        ],
        "label": "Bootstrap latest",
        "group": "Bootstrap"
    },
    {
        "url": "http://ajax.googleapis.com/ajax/libs/prototype/1/prototype.js",
        "label": "Prototype latest",
        "group": "Prototype"
    },
    {
        "url": "http://ajax.googleapis.com/ajax/libs/prototype/1.7.1/prototype.js",
        "label": "Prototype 1.7.1",
        "group": "Prototype"
    },
    {
        "url": "http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js",
        "label": "Prototype 1.6.1.0",
        "group": "Prototype"
    },
    {
        "url": [
            "http://ajax.googleapis.com/ajax/libs/prototype/1/prototype.js",
            "http://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.3/scriptaculous.js"
        ],
        "label": "script.aculo.us 1.8.3",
        "group": "Prototype"
    },
    {
        "url": "http://yui.yahooapis.com/3.7.2/build/yui/yui-min.js",
        "label": "YUI 3.7.2",
        "group": "YUI"
    },
    {
        "url": "http://yui.yahooapis.com/2.9.0/build/yuiloader/yuiloader-min.js",
        "label": "YUI 2.9.0",
        "group": "YUI"
    },
    {
        "url": "http://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools-yui-compressed.js",
        "label": "MooTools 1.4.5",
        "group": "MooTools"
    },
    {
        "url": "http://ajax.googleapis.com/ajax/libs/mootools/1.3.2/mootools-yui-compressed.js",
        "label": "MooTools 1.3.2",
        "group": "MooTools"
    },
    {
        "url": "http://ajax.googleapis.com/ajax/libs/dojo/1.6.0/dojo/dojo.xd.js",
        "label": "Dojo 1.6.0",
        "group": "Dojo"
    },
    {
        "url": "http://ajax.googleapis.com/ajax/libs/dojo/1.4.1/dojo/dojo.xd.js",
        "label": "Dojo 1.4.1",
        "group": "Dojo"
    },
    {
        "url": [
            "http://cdn.kendostatic.com/2012.2.710/styles/kendo.common.min.css",
            "http://cdn.kendostatic.com/2012.2.710/styles/kendo.default.min.css",
            "http://cdn.kendostatic.com/2012.2.710/styles/kendo.dataviz.min.css",
            "http://cdn.kendostatic.com/2012.2.710/styles/kendo.mobile.all.min.css",
            "http://code.jquery.com/jquery-1.8.0.min.js",
            "http://cdn.kendostatic.com/2012.2.710/js/kendo.all.min.js"
        ],
        "label": "Kendo UI Q2 2012",
        "group": "Kendo UI"
    },
    {
        "url": [
            "http://cdn.kendostatic.com/2012.1.322/styles/kendo.common.min.css",
            "http://cdn.kendostatic.com/2012.1.322/styles/kendo.default.min.css",
            "http://cdn.kendostatic.com/2012.1.322/styles/kendo.dataviz.min.css",
            "http://cdn.kendostatic.com/2012.1.322/styles/kendo.mobile.all.min.css",
            "http://code.jquery.com/jquery-1.8.0.min.js",
            "http://cdn.kendostatic.com/2012.1.322/js/kendo.all.min.js"
        ],
        "label": "Kendo UI Q1 2012",
        "group": "Kendo UI"
    },
    {
        "url" : [
            "http://code.jquery.com/qunit/qunit-git.css",
            "http://code.jquery.com/qunit/qunit-git.js"
        ],
        "label": "QUnit",
        "group": "Testing"
    },
    {
        "url":"http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js",
        "label": "Angular 1.0.1"
    },
    {
        "url": [
            "http://documentcloud.github.com/underscore/underscore-min.js",
            "http://documentcloud.github.com/backbone/backbone-min.js"
        ],
        "label": "Backbone 0.9.2"
    },
    {
        "url": "//cdnjs.cloudflare.com/ajax/libs/bonsai/0.4/bonsai.min.js",
        "label": "Bonsai 0.4.0"
    },
    {
        "url": "http://jashkenas.github.com/coffee-script/extras/coffee-script.js",
        "label": "CoffeeScript"
    },
    {
        "url": "https://github.com/downloads/emberjs/ember.js/ember-0.9.8.1.min.js",
        "label": "Ember.js 0.9.8.1"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/es5-shim/1.2.4/es5-shim.min.js",
        "label": "ES5 shim 1.2.4"
    },
    {
        "url": [
            "http://extjs.cachefly.net/ext-3.1.0/resources/css/ext-all.css",
            "http://cdnjs.cloudflare.com/ajax/libs/ext-core/3.1.0/ext-core.js"
        ],
        "label": "ext-core 3.1.0"
    },
    {
        "url": "http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-2.1.0.js",
        "label": "Knockout 2.1"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/less.js/1.1.3/less-1.1.3.min.js",
        "label": "Less 1.1.3"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/lodash.js/0.5.2/lodash.min.js",
        "label": "lodash 0.5.2"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/modernizr/2.5.3/modernizr.min.js",
        "label": "Modernizr 2.5.3"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.6/prefixfree.min.js",
        "label": "Prefixfree 1.0.6"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/processing.js/1.3.6/processing-api.min.js",
        "label": "Processing 1.3.6"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/raphael/2.0.0/raphael-min.js",
        "label": "Raphaël 2.0.0"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/sammy.js/0.6.3/sammy.min.js",
        "label": "Sammy 0.6.3"
    },
    {
        "url": [
            "http://cdn.sencha.io/touch/1.1.0/resources/css/sencha-touch.css",
            "http://cdn.sencha.io/touch/1.1.0/sencha-touch.js"
        ],
        "label": "Sencha Touch"
    },
    {
        "url": [
            "http://traceur-compiler.googlecode.com/git/src/traceur.js",
            "http://traceur-compiler.googlecode.com/git/src/bootstrap.js"
        ],
        "label": "Traceur"
    },
    {
        "url": "http://remy.github.com/twitterlib/twitterlib.min.js",
        "label": "TwitterLib"
    },
    {
        "url": "http://documentcloud.github.com/underscore/underscore-min.js",
        "label": "underscore 1.3.1"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/zepto/0.7/zepto.min.js",
        "label": "Zepto 0.7"
    },
    {
        "url":[
            "http://code.jquery.com/jquery-1.7.1.min.js",
            " http://canjs.us/release/latest/can.jquery.js"
        ],
        "label": "CanJS 1.0.7 for jQuery"
    }
];

window.libraries = libraries; // expose a command line API

libraries.userSpecified = JSON.parse(localStorage.getItem('libraries') || "[]");
for (var i = 0; i < libraries.userSpecified.length; i++) {
  libraries.push(libraries.userSpecified[i]);
}

libraries.add = function (lib) {
  // save to localStorage
  lib.group = 'Custom';
  this.userSpecified.push(lib);
  try {
    localStorage.setItem('libraries', JSON.stringify(this.userSpecified));
  } catch (e) {} // just in case of DOM_22 error, makes me so sad to use this :(
  libraries.push(lib);
  $('#library').trigger('init');
};

libraries.clear = function () {
  libraries.userSpecified = [];
  localStorage.removeItem('libraries');
  var length = libraries.length;
  for (var i = 0; i < length; i++) {
    if (libraries[i].group === 'Custom') {
      libraries.splice(i, 1);
      length--;
    }
  }
  // force a refresh?
  $('#library').trigger('init');
};
<commit_msg>Updated label.<commit_after>//= require "../chrome/storage"

var libraries = [
    {
        "url": "http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js",
        "label": "jQuery latest",
        "group": "jQuery"
    },
    {
        "url": "http://code.jquery.com/jquery-git.js",
        "label": "jQuery WIP (via git)",
        "group": "jQuery"
    },
    {
        "url": "http://code.jquery.com/jquery-1.8.1.min.js",
        "label": "jQuery 1.8.1",
        "group": "jQuery"
    },
    {
        "url": "http://code.jquery.com/jquery-1.7.2.min.js",
        "label": "jQuery 1.7.2",
        "group": "jQuery"
    },
    {
        "url": [
            "http://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/base/jquery-ui.css",
            "http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js",
            "http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"
        ],
        "label": "jQuery UI latest",
        "group": "jQuery UI"
    },
    {
        "url": [
            "http://code.jquery.com/ui/jquery-ui-git.css",
            "http://code.jquery.com/jquery-git.js",
            "http://code.jquery.com/ui/jquery-ui-git.js"
        ],
        "label": "jQuery UI WIP (via git)",
        "group": "jQuery UI"
    },
    {
        "url": [
            "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/themes/base/jquery-ui.css",
            "http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js",
            "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js"
        ],
        "label": "jQuery UI 1.8.23",
        "group": "jQuery UI"
    },
    {
        "url": [
            "http://code.jquery.com/mobile/latest/jquery.mobile.css",
            "http://code.jquery.com/jquery-1.6.4.min.js",
            "http://code.jquery.com/mobile/latest/jquery.mobile.js"
        ],
        "label": "jQuery Mobile Latest",
        "group": "jQuery Mobile"
    },
    {
        "url": [
            "http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css",
            "http://code.jquery.com/jquery-1.6.4.min.js",
            "http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.js"
        ],
        "label": "jQuery Mobile 1.1.0",
        "group": "jQuery Mobile"
    },
    {
        "url": [
            "http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css",
            "http://code.jquery.com/jquery-1.6.4.min.js",
            "http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.1.min.js"
        ],
        "label": "jQuery Mobile 1.0.1",
        "group": "jQuery Mobile"
    },
    {
        "url": [
            "http://code.jquery.com/jquery.min.js",
            "http://twitter.github.com/bootstrap/assets/css/bootstrap.css",
            "http://twitter.github.com/bootstrap/assets/css/bootstrap-responsive.css",
            "http://twitter.github.com/bootstrap/assets/js/bootstrap.js"
        ],
        "label": "Bootstrap latest",
        "group": "Bootstrap"
    },
    {
        "url": "http://ajax.googleapis.com/ajax/libs/prototype/1/prototype.js",
        "label": "Prototype latest",
        "group": "Prototype"
    },
    {
        "url": "http://ajax.googleapis.com/ajax/libs/prototype/1.7.1/prototype.js",
        "label": "Prototype 1.7.1",
        "group": "Prototype"
    },
    {
        "url": "http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js",
        "label": "Prototype 1.6.1.0",
        "group": "Prototype"
    },
    {
        "url": [
            "http://ajax.googleapis.com/ajax/libs/prototype/1/prototype.js",
            "http://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.3/scriptaculous.js"
        ],
        "label": "script.aculo.us 1.8.3",
        "group": "Prototype"
    },
    {
        "url": "http://yui.yahooapis.com/3.7.2/build/yui/yui-min.js",
        "label": "YUI 3.7.2",
        "group": "YUI"
    },
    {
        "url": "http://yui.yahooapis.com/2.9.0/build/yuiloader/yuiloader-min.js",
        "label": "YUI 2.9.0",
        "group": "YUI"
    },
    {
        "url": "http://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools-yui-compressed.js",
        "label": "MooTools 1.4.5",
        "group": "MooTools"
    },
    {
        "url": "http://ajax.googleapis.com/ajax/libs/mootools/1.3.2/mootools-yui-compressed.js",
        "label": "MooTools 1.3.2",
        "group": "MooTools"
    },
    {
        "url": "http://ajax.googleapis.com/ajax/libs/dojo/1.6.0/dojo/dojo.xd.js",
        "label": "Dojo 1.6.0",
        "group": "Dojo"
    },
    {
        "url": "http://ajax.googleapis.com/ajax/libs/dojo/1.4.1/dojo/dojo.xd.js",
        "label": "Dojo 1.4.1",
        "group": "Dojo"
    },
    {
        "url": [
            "http://cdn.kendostatic.com/2012.2.710/styles/kendo.common.min.css",
            "http://cdn.kendostatic.com/2012.2.710/styles/kendo.default.min.css",
            "http://cdn.kendostatic.com/2012.2.710/styles/kendo.dataviz.min.css",
            "http://cdn.kendostatic.com/2012.2.710/styles/kendo.mobile.all.min.css",
            "http://code.jquery.com/jquery-1.8.0.min.js",
            "http://cdn.kendostatic.com/2012.2.710/js/kendo.all.min.js"
        ],
        "label": "Kendo UI Q2 2012",
        "group": "Kendo UI"
    },
    {
        "url": [
            "http://cdn.kendostatic.com/2012.1.322/styles/kendo.common.min.css",
            "http://cdn.kendostatic.com/2012.1.322/styles/kendo.default.min.css",
            "http://cdn.kendostatic.com/2012.1.322/styles/kendo.dataviz.min.css",
            "http://cdn.kendostatic.com/2012.1.322/styles/kendo.mobile.all.min.css",
            "http://code.jquery.com/jquery-1.8.0.min.js",
            "http://cdn.kendostatic.com/2012.1.322/js/kendo.all.min.js"
        ],
        "label": "Kendo UI Q1 2012",
        "group": "Kendo UI"
    },
    {
        "url" : [
            "http://code.jquery.com/qunit/qunit-git.css",
            "http://code.jquery.com/qunit/qunit-git.js"
        ],
        "label": "QUnit",
        "group": "Testing"
    },
    {
        "url":"http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js",
        "label": "Angular 1.0.1"
    },
    {
        "url": [
            "http://documentcloud.github.com/underscore/underscore-min.js",
            "http://documentcloud.github.com/backbone/backbone-min.js"
        ],
        "label": "Backbone 0.9.2"
    },
    {
        "url": "//cdnjs.cloudflare.com/ajax/libs/bonsai/0.4/bonsai.min.js",
        "label": "Bonsai 0.4.latest"
    },
    {
        "url": "http://jashkenas.github.com/coffee-script/extras/coffee-script.js",
        "label": "CoffeeScript"
    },
    {
        "url": "https://github.com/downloads/emberjs/ember.js/ember-0.9.8.1.min.js",
        "label": "Ember.js 0.9.8.1"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/es5-shim/1.2.4/es5-shim.min.js",
        "label": "ES5 shim 1.2.4"
    },
    {
        "url": [
            "http://extjs.cachefly.net/ext-3.1.0/resources/css/ext-all.css",
            "http://cdnjs.cloudflare.com/ajax/libs/ext-core/3.1.0/ext-core.js"
        ],
        "label": "ext-core 3.1.0"
    },
    {
        "url": "http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-2.1.0.js",
        "label": "Knockout 2.1"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/less.js/1.1.3/less-1.1.3.min.js",
        "label": "Less 1.1.3"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/lodash.js/0.5.2/lodash.min.js",
        "label": "lodash 0.5.2"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/modernizr/2.5.3/modernizr.min.js",
        "label": "Modernizr 2.5.3"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.6/prefixfree.min.js",
        "label": "Prefixfree 1.0.6"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/processing.js/1.3.6/processing-api.min.js",
        "label": "Processing 1.3.6"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/raphael/2.0.0/raphael-min.js",
        "label": "Raphaël 2.0.0"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/sammy.js/0.6.3/sammy.min.js",
        "label": "Sammy 0.6.3"
    },
    {
        "url": [
            "http://cdn.sencha.io/touch/1.1.0/resources/css/sencha-touch.css",
            "http://cdn.sencha.io/touch/1.1.0/sencha-touch.js"
        ],
        "label": "Sencha Touch"
    },
    {
        "url": [
            "http://traceur-compiler.googlecode.com/git/src/traceur.js",
            "http://traceur-compiler.googlecode.com/git/src/bootstrap.js"
        ],
        "label": "Traceur"
    },
    {
        "url": "http://remy.github.com/twitterlib/twitterlib.min.js",
        "label": "TwitterLib"
    },
    {
        "url": "http://documentcloud.github.com/underscore/underscore-min.js",
        "label": "underscore 1.3.1"
    },
    {
        "url": "http://cdnjs.cloudflare.com/ajax/libs/zepto/0.7/zepto.min.js",
        "label": "Zepto 0.7"
    },
    {
        "url":[
            "http://code.jquery.com/jquery-1.7.1.min.js",
            " http://canjs.us/release/latest/can.jquery.js"
        ],
        "label": "CanJS 1.0.7 for jQuery"
    }
];

window.libraries = libraries; // expose a command line API

libraries.userSpecified = JSON.parse(localStorage.getItem('libraries') || "[]");
for (var i = 0; i < libraries.userSpecified.length; i++) {
  libraries.push(libraries.userSpecified[i]);
}

libraries.add = function (lib) {
  // save to localStorage
  lib.group = 'Custom';
  this.userSpecified.push(lib);
  try {
    localStorage.setItem('libraries', JSON.stringify(this.userSpecified));
  } catch (e) {} // just in case of DOM_22 error, makes me so sad to use this :(
  libraries.push(lib);
  $('#library').trigger('init');
};

libraries.clear = function () {
  libraries.userSpecified = [];
  localStorage.removeItem('libraries');
  var length = libraries.length;
  for (var i = 0; i < length; i++) {
    if (libraries[i].group === 'Custom') {
      libraries.splice(i, 1);
      length--;
    }
  }
  // force a refresh?
  $('#library').trigger('init');
};
<|endoftext|>


<commit_before>/**
 *
 */
define(function (require, exports, module) {

    var zhCN = require('datatableZh');
    var editorCN = require('i18n');
    exports.index = function ($, orderTableId,orderInfoTableId) {

       var orderEditCn = $.extend(editorCN, {
            create:{
                title: '新增主订单信息'
            },
            edit: {
                title: '订单编辑'
            },
        });
        //editorCN.edit.title = '确认接单';
        //editorCN.edit.submit = '确认接单';
        var orderEditor = new $.fn.dataTable.Editor({
            ajax: {
                create: {
                    type: 'POST',
                    url: '/customer/sale-order',
                    data: {_token: $('meta[name="_token"]').attr('content')},
                },
                edit: {
                    type: 'PUT',
                    url: '/customer/sale-order/_id_',
                    data: {_token: $('meta[name="_token"]').attr('content')},
                },
                remove: {
                    type: 'DELETE',
                    url: '/customer/sale-order/_id_',
                    data: {_token: $('meta[name="_token"]').attr('content')},
                }
            },
            i18n: orderEditCn,
            table: "#" + orderTableId,
            idSrc: 'id',
            fields: [
                {'label': '订单号', 'name': 'readonly_fbill_no', 'data': 'fbill_no', 'type': 'readonly'},
                {'label': '订单日期', 'name': 'readonly_fdate',  'data': 'fdate', 'type': 'readonly'},
                {'label': '业务员','name':'readonly_femp_id' , 'data': 'employee.fname',  'type': 'readonly'},
                {'label': '门店', 'name':'readonly_fstore_id', 'data': 'store.ffullname',  'type': 'readonly'},
                {'label': '发货状态', 'name': 'fsend_status', 'def': 'C', 'type':'select', 'options':[{ 'label': '已收货', value:'C' }]},
            ]
        });

        var orderTable = $("#" + orderTableId).DataTable({
            dom: "lBfrtip",
            language: zhCN,
            processing: true,
            serverSide: true,
            select: true,
            paging: true,
            rowId: "id",
            ajax: '/customer/sale-order/pagination',
            columns: [
                {'data': 'id'},
                {'data': 'fbill_no'},
                {
                    'data': 'fstore_id',
                    render: function (data, type, full) {
                        if (full.store != null)
                            return full.store.ffullname
                        else
                            return "";
                    }
                },
                {'data': 'fdate'},
                {
                    'data': 'femp_id',
                    render: function (data, type, full) {
                        if (full.employee != null)
                            return full.employee.fname
                        else
                            return "";
                    }
                },
                {
                    'data': 'fcust_id',
                    render: function (data, type, full) {
                        if (full.customer != null)
                            return full.customer.fname
                        else
                            return "";
                    }
                },
                {
                    'data': 'fsend_status',
                    render: function (data, type, full) {
                        return send_status(data);
                    }
                },
                {'data': 'source'},
            ],
            columnDefs: [
                {
                    "targets": [0],
                    "visible": false
                }
            ],
            buttons: [
                // { text: '新增', action: function () { }  },
                // { text: '编辑', className: 'edit', enabled: false },
                // { text: '删除', className: 'delete', enabled: false },
                {
                    text: '接单',
                    className: 'accept',
                    enabled: false,
                    action: function (e, dt, node, config) {
                        //dt.ajax.reload();
                        layer.confirm('确认接单?', {btn: ['确定', '取消']}, function () {
                            var row = dt.rows('.selected').data();
                            var order = row.length > 0 ? row[0] : null;
                            if(order){
                                $.post('/customer/sale-order/accept/'+ order.id,
                                    {_token: $('meta[name="_token"]').attr('content')},
                                    function (result) {
                                        if(result.data){
                                            layer.msg('接单成功!');
                                            infoTable.ajax.reload();
                                            dt.ajax.reload();
                                        }else{
                                            layer.msg('接单失败, 错误：' + result.error);
                                        }
                                    }
                                )
                            }
                        }, function () {
                            layer.close();
                        })
                    }
                },
                // {extend: "create", text: '新增', editor: orderEditor},
                // {extend: "edit", text: '编辑', editor: orderEditor},
                // {extend: "remove", text: '删除', editor: orderEditor},
                {extend: 'excel', text: '导出Excel'},
                {extend: 'print', text: '打印'},
                {extend: 'colvis', text: '列显示'}
            ]
        });

        editorCN.edit.title = '确认发货数量';
        editorCN.edit.submit = '确认';
        var infoEditor = new $.fn.dataTable.Editor({
            ajax: {
                create: {
                    type: 'POST',
                    url: '/customer/sale-order-item',
                    data: {_token: $('meta[name="_token"]').attr('content')},
                },
                edit: {
                    type: 'PUT',
                    url: '/customer/sale-order-item/_id_',
                    data: {_token: $('meta[name="_token"]').attr('content')},
                },
                remove: {
                    type: 'DELETE',
                    url: '/customer/sale-order-item/_id_',
                    data: {_token: $('meta[name="_token"]').attr('content')},
                }
            },
            i18n: editorCN,
            table: "#" + orderInfoTableId,
            idSrc: 'id',
            fields: [
                {'label': '商品', 'name': 'readonly_material_fname', 'data': 'material.fname',  'type': 'readonly'},
                {'label': '销售单位数量', 'name': 'readonly_fqty', 'data': 'fqty', 'type': 'readonly'},
                {'label': '销售单位', 'name': 'readonly_fsale_unit', 'data': 'fsale_unit', 'type': 'readonly'},
                {'label': '基本单位数量', 'name': 'readonly_fbase_qty',  'data': 'fbase_qty', 'type': 'readonly'},
                {'label': '基本单位', 'name': 'readonly_fbase_unit', 'data': 'fbase_unit', 'type': 'readonly'},
                {'label': '确认销售单位数量', 'name': 'fsend_qty' },
                {'label': '确认基本单位数量', 'name': 'fsend_base_qty' },
            ]
        });

        var infoTable = $("#" + orderInfoTableId).DataTable({
            dom: "Bfrtip",
            language: zhCN,
            processing: true,
            serverSide: true,
            paging: true,
            rowId: "id",
            ajax: {
                url : '/customer/sale-order-item/pagination',
                data : function (data) {
                    var order = orderTable.rows('.selected').data();
                    data.columns[1]['search']['value'] = order.length > 0 ? order[0].id : -1;
                }
            },
            columns: [
                {
                    'data': 'id',
                    render: function (data, type, full) {
                        return '<input type="checkbox" class="editor-active" value="'+data+'">';
                    },
                    className: "dt-body-center"
                },
                {
                    'data': 'fsale_order_id',
                    render: function (data, type, full) {
                            return full.order.fbill_no
                    }
                },
                {
                    'data': 'fmaterial_id',
                    render: function (data, type, full) {
                            return full.material.fname;
                    }
                },
                {'data': 'fqty'},
                {'data': 'fsale_unit'},
                {'data': 'fbase_qty'},
                {'data': 'fbase_unit'},
                {'data': 'fsend_qty'},
                {'data': 'fsend_base_qty'},
                {
                    'data': 'fsend_status',
                    render: function (data, type, full) {
                        return send_status(data);
                    }
                },

            ],
            buttons: [
                {
                    text: '发货数量确认',
                    className: 'sure',
                    enabled: false,
                    action: function (e, dt, node, config) {
                        $('#sureForm').get(0).reset();
                        $('#sureForm').bootstrapValidator('resetForm');
                        var detailrows = infoTable.rows('.selected').data();
                        var detail = detailrows.length > 0 ? detailrows[0] : null;
                        if(detail){
                            $('#id', '#sureForm').val(detail.id);
                            $('#material', '#sureForm').val(detail.material.fname);
                            $('#order_no', '#sureForm').val(detail.order.fbill_no);
                            //$('#unit', '#sureForm').val(detail.id);
                            addOptions(document.getElementById('unit'),
                                [
                                    { text: detail.material.fsale_unit, value:  'sale_unit' },
                                    { text: detail.material.fbase_unit, value:  'base_unit' }
                                ]
                            );
                            $('#sureForm').attr('')
                            $('#sureFormDialog').modal('show');
                        }
                    }
                },
                {
                    text: '确认配送',
                    className: 'send',
                    enabled: false,
                    action: function (e, dt, node, config) {
                        layer.confirm('确认配送?', {btn: ['确定', '取消']}, function () {
                            var orders = dt.rows('.selected').data();

                            if(orders.length > 0){
                                var ids = [] ;
                                var orderId = 0
                                for(var i = 0; i < orders.length; i++){
                                    ids[ids.length] = orders[i].id;
                                }
                                orderId = orders[0].fsale_order_id;
                                $.post('/customer/sale-order-item/send',
                                    {_token: $('meta[name="_token"]').attr('content'), ids: ids, order_id: orderId},
                                    function (result) {
                                        if(result.data){
                                            layer.msg('确认配送成功!');
                                            dt.ajax.reload();
                                            orderTable.ajax.reload();
                                        }else{
                                            layer.msg('确认配送失败, 错误：' + result.error);
                                        }
                                    }
                                )
                            }
                        }, function () {
                            layer.close();
                        })
                    }
                },
                // {extend: "create", text: '新增', editor: infoEditor, enabled: false},
                // {extend: "edit", text: '编辑', editor: infoEditor, enabled: false},
                // {extend: "remove", text: '删除', editor: infoEditor, enabled: false},
                {extend: 'excel', text: '导出Excel'},
                {extend: 'print', text: '打印'},
                {extend: 'colvis', text: '列显示'}
            ],
            columnDefs: [
                {
                    'targets': 0,
                    'checkboxes': {
                        'selectRow': true
                    }
                }
            ],
            select: {
                'style': 'multi'
            },
            order: [[ 1, 'asc' ]]
        });

        orderTable.on( 'select', orderTableRowSelect).on( 'deselect', orderTableRowSelect);

        function orderTableRowSelect() {
            var row = orderTable.rows('.selected').data();
            var order = row.length > 0 ? row[0] : null;
            //console.log(order);
            if(order){
                infoTable.columns( 1 ).search( order.id ).draw();
                orderTable.buttons( ['.accept'] ).enable(order.fsend_status == 'A');
                orderTable.buttons( ['.buttons-edit'] ).enable(order.source != 'phone');
                orderTable.buttons( ['.buttons-remove'] ).enable(order.source != 'phone' && order.fsend_status == 'A');
            }
        }

        infoTable.on( 'select', infoTableRowSelect).on( 'deselect', infoTableRowSelect);

        function infoTableRowSelect() {
            var row = orderTable.rows('.selected').data();
            var order = row.length > 0 ? row[0] : null;

            var detailrows = infoTable.rows('.selected').data();
            var detail = detailrows.length > 0 ? detailrows[0] : null;
            //console.log(order);
            if(order && detail){
                infoTable.buttons( ['.buttons-create', '.buttons-edit','.buttons-remove']).enable(order.source != 'phone' && detail.fsend_status == 'A');
                infoTable.buttons( ['.sure', '.send']).enable(detail.fsend_status == 'B');
            }
        }

        //
        $('#sureForm').bootstrapValidator({
            message: 'This value is not valid',
            feedbackIcons: {
                valid: 'glyphicon glyphicon-ok',
                invalid: 'glyphicon glyphicon-remove',
                validating: 'glyphicon glyphicon-refresh'
            },
            fields: {
                qty: {
                    validators: {
                        notEmpty: {},
                        numeric: {}
                    }
                },
            }
        }).on('success.form.bv', function (e) {
            // Prevent form submission
            e.preventDefault();
            // Get the form instance
            var $form = $(e.target);
            // Get the BootstrapValidator instance
            var bv = $form.data('bootstrapValidator');
            // Use Ajax to submit form data
            //var data = $form.serialize();
            //console.log(data);
            $.post($form.attr('action') + '/' + $('#id', '#sureForm').val(), $form.serialize(), function (result) {
                if(result.data)
                {
                    layer.msg('保存成功!');
                    infoTable.ajax.reload();
                    $('#sureFormDialog').modal('hide');
                }
            }, 'json');
        });
    }

});<commit_msg>bug fix<commit_after>/**
 *
 */
define(function (require, exports, module) {

    var zhCN = require('datatableZh');
    var editorCN = require('i18n');
    exports.index = function ($, orderTableId,orderInfoTableId) {

       var orderEditCn = $.extend(editorCN, {
            create:{
                title: '新增主订单信息',
                button: "新建",
                submit: "提交"
            },
            edit: {
                title: '订单编辑',
                button: "新建",
                submit: "提交"
            },
        });
        //editorCN.edit.title = '确认接单';
        //editorCN.edit.submit = '确认接单';
        var orderEditor = new $.fn.dataTable.Editor({
            ajax: {
                create: {
                    type: 'POST',
                    url: '/customer/sale-order',
                    data: {_token: $('meta[name="_token"]').attr('content')},
                },
                edit: {
                    type: 'PUT',
                    url: '/customer/sale-order/_id_',
                    data: {_token: $('meta[name="_token"]').attr('content')},
                },
                remove: {
                    type: 'DELETE',
                    url: '/customer/sale-order/_id_',
                    data: {_token: $('meta[name="_token"]').attr('content')},
                }
            },
            i18n: orderEditCn,
            table: "#" + orderTableId,
            idSrc: 'id',
            fields: [
                {'label': '订单号', 'name': 'readonly_fbill_no', 'data': 'fbill_no', 'type': 'readonly'},
                {'label': '订单日期', 'name': 'readonly_fdate',  'data': 'fdate', 'type': 'readonly'},
                {'label': '业务员','name':'readonly_femp_id' , 'data': 'employee.fname',  'type': 'readonly'},
                {'label': '门店', 'name':'readonly_fstore_id', 'data': 'store.ffullname',  'type': 'readonly'},
                {'label': '发货状态', 'name': 'fsend_status', 'def': 'C', 'type':'select', 'options':[{ 'label': '已收货', value:'C' }]},
            ]
        });

        var orderTable = $("#" + orderTableId).DataTable({
            dom: "lBfrtip",
            language: zhCN,
            processing: true,
            serverSide: true,
            select: true,
            paging: true,
            rowId: "id",
            ajax: '/customer/sale-order/pagination',
            columns: [
                {'data': 'id'},
                {'data': 'fbill_no'},
                {
                    'data': 'fstore_id',
                    render: function (data, type, full) {
                        if (full.store != null)
                            return full.store.ffullname
                        else
                            return "";
                    }
                },
                {'data': 'fdate'},
                {
                    'data': 'femp_id',
                    render: function (data, type, full) {
                        if (full.employee != null)
                            return full.employee.fname
                        else
                            return "";
                    }
                },
                {
                    'data': 'fcust_id',
                    render: function (data, type, full) {
                        if (full.customer != null)
                            return full.customer.fname
                        else
                            return "";
                    }
                },
                {
                    'data': 'fsend_status',
                    render: function (data, type, full) {
                        return send_status(data);
                    }
                },
                {'data': 'source'},
            ],
            columnDefs: [
                {
                    "targets": [0],
                    "visible": false
                }
            ],
            buttons: [
                // { text: '新增', action: function () { }  },
                // { text: '编辑', className: 'edit', enabled: false },
                // { text: '删除', className: 'delete', enabled: false },
                {
                    text: '接单',
                    className: 'accept',
                    enabled: false,
                    action: function (e, dt, node, config) {
                        //dt.ajax.reload();
                        layer.confirm('确认接单?', {btn: ['确定', '取消']}, function () {
                            var row = dt.rows('.selected').data();
                            var order = row.length > 0 ? row[0] : null;
                            if(order){
                                $.post('/customer/sale-order/accept/'+ order.id,
                                    {_token: $('meta[name="_token"]').attr('content')},
                                    function (result) {
                                        if(result.data){
                                            layer.msg('接单成功!');
                                            infoTable.ajax.reload();
                                            dt.ajax.reload();
                                        }else{
                                            layer.msg('接单失败, 错误：' + result.error);
                                        }
                                    }
                                )
                            }
                        }, function () {
                            layer.close();
                        })
                    }
                },
                {extend: "create", text: '新增', editor: orderEditor},
                {extend: "edit", text: '编辑', editor: orderEditor},
                {extend: "remove", text: '删除', editor: orderEditor},
                {extend: 'excel', text: '导出Excel'},
                {extend: 'print', text: '打印'},
                {extend: 'colvis', text: '列显示'}
            ]
        });

        editorCN.edit.title = '确认发货数量';
        editorCN.edit.submit = '确认';
        var infoEditor = new $.fn.dataTable.Editor({
            ajax: {
                create: {
                    type: 'POST',
                    url: '/customer/sale-order-item',
                    data: {_token: $('meta[name="_token"]').attr('content')},
                },
                edit: {
                    type: 'PUT',
                    url: '/customer/sale-order-item/_id_',
                    data: {_token: $('meta[name="_token"]').attr('content')},
                },
                remove: {
                    type: 'DELETE',
                    url: '/customer/sale-order-item/_id_',
                    data: {_token: $('meta[name="_token"]').attr('content')},
                }
            },
            i18n: editorCN,
            table: "#" + orderInfoTableId,
            idSrc: 'id',
            fields: [
                {'label': '商品', 'name': 'readonly_material_fname', 'data': 'material.fname',  'type': 'readonly'},
                {'label': '销售单位数量', 'name': 'readonly_fqty', 'data': 'fqty', 'type': 'readonly'},
                {'label': '销售单位', 'name': 'readonly_fsale_unit', 'data': 'fsale_unit', 'type': 'readonly'},
                {'label': '基本单位数量', 'name': 'readonly_fbase_qty',  'data': 'fbase_qty', 'type': 'readonly'},
                {'label': '基本单位', 'name': 'readonly_fbase_unit', 'data': 'fbase_unit', 'type': 'readonly'},
                {'label': '确认销售单位数量', 'name': 'fsend_qty' },
                {'label': '确认基本单位数量', 'name': 'fsend_base_qty' },
            ]
        });

        var infoTable = $("#" + orderInfoTableId).DataTable({
            dom: "Bfrtip",
            language: zhCN,
            processing: true,
            serverSide: true,
            paging: true,
            rowId: "id",
            ajax: {
                url : '/customer/sale-order-item/pagination',
                data : function (data) {
                    var order = orderTable.rows('.selected').data();
                    data.columns[1]['search']['value'] = order.length > 0 ? order[0].id : -1;
                }
            },
            columns: [
                {
                    'data': 'id',
                    render: function (data, type, full) {
                        return '<input type="checkbox" class="editor-active" value="'+data+'">';
                    },
                    className: "dt-body-center"
                },
                {
                    'data': 'fsale_order_id',
                    render: function (data, type, full) {
                            return full.order.fbill_no
                    }
                },
                {
                    'data': 'fmaterial_id',
                    render: function (data, type, full) {
                            return full.material.fname;
                    }
                },
                {'data': 'fqty'},
                {'data': 'fsale_unit'},
                {'data': 'fbase_qty'},
                {'data': 'fbase_unit'},
                {'data': 'fsend_qty'},
                {'data': 'fsend_base_qty'},
                {
                    'data': 'fsend_status',
                    render: function (data, type, full) {
                        return send_status(data);
                    }
                },

            ],
            buttons: [
                {
                    text: '发货数量确认',
                    className: 'sure',
                    enabled: false,
                    action: function (e, dt, node, config) {
                        $('#sureForm').get(0).reset();
                        $('#sureForm').bootstrapValidator('resetForm');
                        var detailrows = infoTable.rows('.selected').data();
                        var detail = detailrows.length > 0 ? detailrows[0] : null;
                        if(detail){
                            $('#id', '#sureForm').val(detail.id);
                            $('#material', '#sureForm').val(detail.material.fname);
                            $('#order_no', '#sureForm').val(detail.order.fbill_no);
                            //$('#unit', '#sureForm').val(detail.id);
                            addOptions(document.getElementById('unit'),
                                [
                                    { text: detail.material.fsale_unit, value:  'sale_unit' },
                                    { text: detail.material.fbase_unit, value:  'base_unit' }
                                ]
                            );
                            $('#sureForm').attr('')
                            $('#sureFormDialog').modal('show');
                        }
                    }
                },
                {
                    text: '确认配送',
                    className: 'send',
                    enabled: false,
                    action: function (e, dt, node, config) {
                        layer.confirm('确认配送?', {btn: ['确定', '取消']}, function () {
                            var orders = dt.rows('.selected').data();

                            if(orders.length > 0){
                                var ids = [] ;
                                var orderId = 0
                                for(var i = 0; i < orders.length; i++){
                                    ids[ids.length] = orders[i].id;
                                }
                                orderId = orders[0].fsale_order_id;
                                $.post('/customer/sale-order-item/send',
                                    {_token: $('meta[name="_token"]').attr('content'), ids: ids, order_id: orderId},
                                    function (result) {
                                        if(result.data){
                                            layer.msg('确认配送成功!');
                                            dt.ajax.reload();
                                            orderTable.ajax.reload();
                                        }else{
                                            layer.msg('确认配送失败, 错误：' + result.error);
                                        }
                                    }
                                )
                            }
                        }, function () {
                            layer.close();
                        })
                    }
                },
                {extend: "create", text: '新增', editor: infoEditor, enabled: false},
                {extend: "edit", text: '编辑', editor: infoEditor, enabled: false},
                {extend: "remove", text: '删除', editor: infoEditor, enabled: false},
                {extend: 'excel', text: '导出Excel'},
                {extend: 'print', text: '打印'},
                {extend: 'colvis', text: '列显示'}
            ],
            columnDefs: [
                {
                    'targets': 0,
                    'checkboxes': {
                        'selectRow': true
                    }
                }
            ],
            select: {
                'style': 'multi'
            },
            order: [[ 1, 'asc' ]]
        });

        orderTable.on( 'select', orderTableRowSelect).on( 'deselect', orderTableRowSelect);

        function orderTableRowSelect() {
            var row = orderTable.rows('.selected').data();
            var order = row.length > 0 ? row[0] : null;
            //console.log(order);
            if(order){
                infoTable.columns( 1 ).search( order.id ).draw();
                orderTable.buttons( ['.accept'] ).enable(order.fsend_status == 'A');
                orderTable.buttons( ['.buttons-edit'] ).enable(order.source != 'phone');
                orderTable.buttons( ['.buttons-remove'] ).enable(order.source != 'phone' && order.fsend_status == 'A');
            }
        }

        infoTable.on( 'select', infoTableRowSelect).on( 'deselect', infoTableRowSelect);

        function infoTableRowSelect() {
            var row = orderTable.rows('.selected').data();
            var order = row.length > 0 ? row[0] : null;

            var detailrows = infoTable.rows('.selected').data();
            var detail = detailrows.length > 0 ? detailrows[0] : null;
            //console.log(order);
            if(order && detail){
                infoTable.buttons( ['.buttons-create', '.buttons-edit','.buttons-remove']).enable(order.source != 'phone' && detail.fsend_status == 'A');
                infoTable.buttons( ['.sure', '.send']).enable(detail.fsend_status == 'B');
            }
        }

        //
        $('#sureForm').bootstrapValidator({
            message: 'This value is not valid',
            feedbackIcons: {
                valid: 'glyphicon glyphicon-ok',
                invalid: 'glyphicon glyphicon-remove',
                validating: 'glyphicon glyphicon-refresh'
            },
            fields: {
                qty: {
                    validators: {
                        notEmpty: {},
                        numeric: {}
                    }
                },
            }
        }).on('success.form.bv', function (e) {
            // Prevent form submission
            e.preventDefault();
            // Get the form instance
            var $form = $(e.target);
            // Get the BootstrapValidator instance
            var bv = $form.data('bootstrapValidator');
            // Use Ajax to submit form data
            //var data = $form.serialize();
            //console.log(data);
            $.post($form.attr('action') + '/' + $('#id', '#sureForm').val(), $form.serialize(), function (result) {
                if(result.data)
                {
                    layer.msg('保存成功!');
                    infoTable.ajax.reload();
                    $('#sureFormDialog').modal('hide');
                }
            }, 'json');
        });
    }

});<|endoftext|>


<commit_before>//Chris Samuel
//Github: Alayode
//2015-3-12

// Code School: Changing Declarations to Expressions

// Developers for the Forest of Function Expressions
// Theme Park have created a function declaration named forestFright,
// but they’ve decided not to keep the function in memory.
// Convert the function from a named function
// declaration to an anonymous function
// expression and assign it to a variable called runAway.

function forestFright() {
  var toAlert = "";
  for (var i = 0; i < 5; i++) {
    toAlert = toAlert + "Lions, Tigers, and Bears, Oh My!!\n";
  }
  alert(toAlert);
}

// First lets create a variable called runAway
var runAway;

//Next lets try remeber that when a function expression is added to a
//variable we can remove the name of the function from the "()"
// this will make it become an anonymous function.

function() {
  var toAlert = "";
  for (var i = 0; i < 5; i++) {
    toAlert = toAlert + "Lions, Tigers, and Bears, Oh My!!\n";
  }
  alert(toAlert);
}

// now that it has no name it can called by assiging it to a
// variable. lets use the variable runAway

//this is another to use this function.
var runAway = function() {
  var toAlert = "";
  for (var i = 0; i < 5; i++) {
    toAlert = toAlert + "Lions, Tigers, and Bears, Oh My!!\n";
  }
  alert(toAlert);
};

//Finally we will callback the function by adding the name of the variable plus the paraentheses
//to call back the function.
//callback
runAway();
<commit_msg>COMMENTED OUT CALLBACK<commit_after>//Chris Samuel
//Github: Alayode
//2015-3-12

// Code School: Changing Declarations to Expressions

// Developers for the Forest of Function Expressions
// Theme Park have created a function declaration named forestFright,
// but they’ve decided not to keep the function in memory.
// Convert the function from a named function
// declaration to an anonymous function
// expression and assign it to a variable called runAway.

function forestFright() {
  var toAlert = "";
  for (var i = 0; i < 5; i++) {
    toAlert = toAlert + "Lions, Tigers, and Bears, Oh My!!\n";
  }
  alert(toAlert);
}

// First lets create a variable called runAway
var runAway;

//Next lets try remeber that when a function expression is added to a
//variable we can remove the name of the function from the "()"
// this will make it become an anonymous function.

function() {
  var toAlert = "";
  for (var i = 0; i < 5; i++) {
    toAlert = toAlert + "Lions, Tigers, and Bears, Oh My!!\n";
  }
  alert(toAlert);
}

// now that it has no name it can called by assiging it to a
// variable. lets use the variable runAway

//this is another to use this function.
var runAway = function() {
  var toAlert = "";
  for (var i = 0; i < 5; i++) {
    toAlert = toAlert + "Lions, Tigers, and Bears, Oh My!!\n";
  }
  alert(toAlert);
};

//Finally we will callback the function by adding the name of the variable plus the paraentheses
//to call back the function.
//callback
// runAway();
<|endoftext|>


<commit_before>//////////// load required libraries
var url = require('url'),
	http = require('http'),
	path = require('path'),
    fs = require('fs'),
	WAMS = require(path.resolve('libs/wams-server.js')); // When using this example as base, make sure that this points to the correct WAMS server library path.

//////////// web server section

// Set up required variables
var homeDir = path.resolve(process.cwd(), '.');
var stat404 = fs.readFileSync(path.join(homeDir, '/status_404.html'));

// HTTP-server main function (handle incoming requests and serves files)
var serverFunc = function (req, res) {

	var uri = url.parse(req.url).pathname;
	if (uri == "/") uri = "/index.html";
	file = fs.readFile(path.join(homeDir, uri), function (err, data) {
		if (err) { // If file doesn't exist, serve 404 error.
			res.writeHead(404, {'Content-Type': 'text/html', 'Content-Length': stat404.length});
			res.end(stat404);
		}
		else {
			switch (/.*\.([^\?.]*).*/.exec(uri)[1]) { // extract file type
				case "htm":
				case "html":
					// handler for HTML-files
					res.writeHead(200, {'Content-Type': 'text/html', 'Content-Length': data.length}); break;
				case "js":
					// handler for JavsScript-files
					res.writeHead(200, {'Content-Type': 'application/javascript', 'Content-Length': data.length}); break;
				default:
					// handler for all other file types
					res.writeHead(200, {'Content-Type': 'text/plain', 'Content-Length': data.length}); break;
			}
			res.end(data);
		}
	});
};

//////////// WAMS section

// Set up HTTP-server: listen on port 8080 and use serverFunc (see above) to serve files to clients.
var httpServer = http.createServer(serverFunc).listen(3000);

// Start WAMS using the HTTP-server
WAMS.listen(httpServer);

WAMS.on("newCard", onNewCard);
WAMS.on("updateUserView", onUpdateUserView);
WAMS.on("updateCard", onUpdateCard);
WAMS.on("consoleLog", onConsoleLog);

var cardID = 0;

function onNewCard(data) {
	data.data.id = cardID;
	cardID++;
	WAMS.emit("newCard", data);
}

function onUpdateUserView(data) {
	WAMS.emit("updateUserView", data);
}

function onUpdateCard(data){
	WAMS.emit("updateCard", data);
}

function onConsoleLog(consoleMessage){
	console.log(consoleMessage.source+ ": " + consoleMessage.data);
}
<commit_msg>Update(Minor): Initializes to current drawings<commit_after>//////////// load required libraries
var url = require('url'),
	http = require('http'),
	path = require('path'),
    fs = require('fs'),
	WAMS = require(path.resolve('libs/wams-server.js')); // When using this example as base, make sure that this points to the correct WAMS server library path.

//////////// web server section

// Set up required variables
var homeDir = path.resolve(process.cwd(), '.');
var stat404 = fs.readFileSync(path.join(homeDir, '/status_404.html'));

// HTTP-server main function (handle incoming requests and serves files)
var serverFunc = function (req, res) {

	var uri = url.parse(req.url).pathname;

	// ---------- Choose your server file here-----------------------------------
	if (uri == "/") uri = "/freeflow.html";
	// --------------------------------------------------------------------------

	file = fs.readFile(path.join(homeDir, uri), function (err, data) {
		if (err) { // If file doesn't exist, serve 404 error.
			res.writeHead(404, {'Content-Type': 'text/html', 'Content-Length': stat404.length});
			res.end(stat404);
		}
		else {
			switch (/.*\.([^\?.]*).*/.exec(uri)[1]) { // extract file type
				case "htm":
				case "html":
					// handler for HTML-files
					res.writeHead(200, {'Content-Type': 'text/html', 'Content-Length': data.length}); break;
				case "js":
					// handler for JavsScript-files
					res.writeHead(200, {'Content-Type': 'application/javascript', 'Content-Length': data.length}); break;
				default:
					// handler for all other file types
					res.writeHead(200, {'Content-Type': 'text/plain', 'Content-Length': data.length}); break;
			}
			console.log("Started server with model: " + uri);
			res.end(data);
		}
	});
};

//////////// WAMS section

// Set up HTTP-server: listen on port 8080 and use serverFunc (see above) to serve files to clients.
var httpServer = http.createServer(serverFunc).listen(3000);

// Start WAMS using the HTTP-server
WAMS.listen(httpServer);

WAMS.on("newCard", onNewCard);
WAMS.on("updateUserView", onUpdateUserView);
WAMS.on("updateCard", onUpdateCard);
WAMS.on("consoleLog", onConsoleLog);
WAMS.on("needOldCards", onNeedOldCards);
WAMS.on("oldCards", onOldCards);

var cardID = 0;

function onNewCard(data) {
	data.data.id = cardID;
	cardID++;
	WAMS.emit("newCard", data);
}

function onUpdateUserView(data) {
	WAMS.emit("updateUserView", data);
}

function onUpdateCard(data){
	WAMS.emit("updateCard", data);
}

function onConsoleLog(consoleMessage){
	console.log(consoleMessage.source+ ": " + consoleMessage.data);
}

function onNeedOldCards(position){
	WAMS.emit("needOldCards", position);
}

function onOldCards(data){
	WAMS.emit("oldCards", data);
}
<|endoftext|>