<commit_before>/*
 Trivial Components (https://github.com/trivial-components/trivial-components)

 Copyright 2015 Yann Massard (https://github.com/yamass) and other contributors

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
(function (factory) {
        "use strict";

        if (typeof define === 'function' && define.amd) {
            // Define as an AMD module if possible
            define('trivial-unitbox', ['trivial-core', 'jquery', 'mustache'], factory);
        } else if (typeof exports === 'object') {
            // Node/CommonJS
            module.exports = factory(require('trivial-core'), require('jquery'), require('mustache'));
        } else if (jQuery && !jQuery.fn.trivialunitbox) {
            // Define using browser globals otherwise
            // Prevent multiple instantiations if the script is loaded twice
            factory(TrivialComponents, jQuery, Mustache);
        }
    }(function (TrivialComponents, $, Mustache) {

        var keyCodes = TrivialComponents.keyCodes;

        function TrivialUnitBox(originalInput, options) {
            options = options || {};
            var config = $.extend({
                unitValueProperty: null,
                decimalSeparator: '.',
                numberUnitValueSeparatorString: ' ',
                inputTextProperty: 'code',
                template: TrivialComponents.currency2LineTemplate,
                selectedEntryTemplate: options.template || TrivialComponents.currencySingleLineShortTemplate,
                selectedEntry: undefined,
                spinnerTemplate: TrivialComponents.defaultSpinnerTemplate,
                noEntriesTemplate: TrivialComponents.defaultNoEntriesTemplate,
                entries: null,
                emptyEntry: {},
                queryFunction: null, // defined below...
                autoComplete: false,
                autoCompleteDelay: 0,
                showTrigger: true,
                matchingOptions: {
                    matchingMode: 'prefix-word',
                    ignoreCase: true,
                    maxLevenshteinDistance: 2
                }
            }, options);

            config.queryFunction = config.queryFunction || TrivialComponents.defaultListQueryFunctionFactory(config.entries || [], config.matchingOptions);

            var listBox;
            var isDropDownOpen = false;
            var entries = config.entries;
            var selectedEntry = null;
            var blurCausedByClickInsideComponent = false;
            var autoCompleteTimeoutId = -1;
            var doNoAutoCompleteBecauseBackspaceWasPressed = false;

            var $spinners = $();
            var $originalInput = $(originalInput);
            var $unitBox = $('
').insertAfter($originalInput);
            var $selectedEntryAndTriggerWrapper = $('
').appendTo($unitBox);
            var $selectedEntryWrapper = $('
').appendTo($selectedEntryAndTriggerWrapper);
            if (config.showTrigger) {
                var $trigger = $('

').appendTo($selectedEntryAndTriggerWrapper);
                $trigger.mousedown(function () {
                    if (isDropDownOpen) {
                        closeDropDown();
                    } else {
                        setTimeout(function () { // TODO remove this when Chrome bug is fixed. Chrome scrolls to the top of the page if we do this synchronously. Maybe this has something to do with https://code.google.com/p/chromium/issues/detail?id=342307 .
                            openDropDown();
                            if (entries == null) {
                                query();
                            }
                        });
                    }
                });
            }
            var $dropDown = $('

').appendTo("body");
            var $editor;
            if (config.valueProperty) {
                $originalInput.addClass("tr-original-input");
                $editor = $('<input type="text"/>');
            } else {
                $editor = $originalInput;
            }

            $editor.prependTo($unitBox).addClass("tr-unitbox-edit-input")
                .focus(function () {
                    if (blurCausedByClickInsideComponent) {
                        // do nothing!
                    } else {
                        $unitBox.addClass('focus');
                    }
                })
                .blur(function () {
                    if (blurCausedByClickInsideComponent) {
                        $editor.focus();
                    } else {
                        $unitBox.removeClass('focus');
                        cleanUpEditorValue();
                        closeDropDown();
                    }
                })
                .keydown(function (e) {
                    if (e.which == keyCodes.tab || TrivialComponents.isModifierKey(e)) {
                        return; // tab or modifier key was pressed...
                    } else if (e.which == keyCodes.left_arrow || e.which == keyCodes.right_arrow) {
                        return; // let the user navigate freely left and right...
                    }

                    if (e.which == keyCodes.backspace || e.which == keyCodes.delete) {
                        console.log("backspace or delete");
                        doNoAutoCompleteBecauseBackspaceWasPressed = true; // we want query results, but no autocomplete
                    }

                    if (e.which == keyCodes.up_arrow || e.which == keyCodes.down_arrow) {
                        openDropDown();
                        var direction = e.which == keyCodes.up_arrow ? -1 : 1;
                        if (entries != null) {
                            listBox.highlightNextEntry(direction);
                            autoCompleteIfPossible(config.autoCompleteDelay);
                            return false; // some browsers move the caret to the beginning on up key
                        } else {
                            query(direction);
                        }
                    } else if (isDropDownOpen && e.which == keyCodes.enter) {
                        selectEntry(listBox.getHighlightedEntry());
                        closeDropDown();
                    } else if (e.which == keyCodes.escape) {
                        closeDropDown();
                        cleanUpEditorValue();
                    }
                })
                .keypress(function (e) {
                    var character = String.fromCharCode(e.which);
                    if (character >= '0' && character <= '9'
                        || character === config.decimalSeparator
                        || character === ' ') {
                        // was number input...
                    } else if (e.which != keyCodes.enter) {
                        //console.log("opening because '" + character + "', which: " + e.which);
                        //openDropDown();
                        //query(1);
                    }
                })
                .keyup(function (e) {
                    if (keyCodes.specialKeys.indexOf(e.which) != -1
                        && e.which != keyCodes.backspace
                        && e.which != keyCodes.delete) {
                        // ignore
                    } else if (getQueryString().length > 0) {
                        openDropDown();
                        query(1);
                    } else {
                        closeDropDown();
                    }
                })
                .mousedown(function () {
                    openDropDown();
                    if (entries == null) {
                        query();
                    }
                });

            $unitBox.add($dropDown).mousedown(function () {
                if ($editor.is(":focus")) {
                    blurCausedByClickInsideComponent = true;
                }
            }).mouseup(function () {
                if (blurCausedByClickInsideComponent) {
                    $editor.focus();
                    blurCausedByClickInsideComponent = false;
                }
            }).mouseout(function () {
                if (blurCausedByClickInsideComponent) {
                    $editor.focus();
                    blurCausedByClickInsideComponent = false;
                }
            });

            listBox = $dropDown.TrivialListBox(config);
            listBox.$.change(function () {
                var selectedListBoxEntry = listBox.getSelectedEntry();
                if (selectedListBoxEntry) {
                    selectEntry(selectedListBoxEntry);
                    listBox.selectEntry(null);
                    closeDropDown();
                }
            });

            selectEntry(config.selectedEntry || null);

            $selectedEntryWrapper.click(function () {
                openDropDown();
                if (entries == null) {
                    query();
                }
            });

            var getQueryString = function () {
                var nonSelectedEditorValue = getNonAutoCompleteEditorValue();
                var firstQueryCharacterIndex = nonSelectedEditorValue.search(new RegExp('[^\\d\\' + config.decimalSeparator + ' ]'));
                if (firstQueryCharacterIndex != -1) {
                    return nonSelectedEditorValue.substr(firstQueryCharacterIndex);
                } else {
                    return "";
                }
            };

            function query(highlightDirection) {
                var $spinner = $(config.spinnerTemplate).appendTo($dropDown);
                $spinners = $spinners.add($spinner);

                // call queryFunction asynchronously to be sure the input field has been updated before the result callback is called. Note: the query() method is called on keydown...
                setTimeout(function () {
                    config.queryFunction(getQueryString(), function (newEntries) {
                        updateEntries(newEntries);

                        var queryString = getQueryString();
                        if (queryString.length > 0) {
                            listBox.highlightTextMatches(queryString);
                            listBox.highlightNextMatchingEntry(highlightDirection);
                        } else {
                            listBox.highlightNextEntry(highlightDirection);
                        }

                        autoCompleteIfPossible(config.autoCompleteDelay);

                        if (isDropDownOpen) {
                            openDropDown(); // only for repositioning!
                        }
                    });
                });
            }

            function fireChangeEvents() {
                $originalInput.trigger("change");
                $unitBox.trigger("change");
            }

            function selectEntry(entry) {
                if (entry == null) {
                    selectedEntry = null;
                    var $selectedEntry = $(Mustache.render(config.selectedEntryTemplate, config.emptyEntry))
                        .addClass("tr-combobox-entry")
                        .addClass("empty");
                    $selectedEntryWrapper.empty().append($selectedEntry);
                } else {
                    selectedEntry = entry;
                    var $selectedEntry = $(Mustache.render(config.selectedEntryTemplate, entry))
                        .addClass("tr-combobox-entry");
                    $selectedEntryWrapper.empty().append($selectedEntry);
                }
                cleanUpEditorValue();
                fireChangeEvents();
            }

            function isEntrySelected() {
                return selectedEntry != null && selectedEntry !== config.emptyEntry;
            }

            function cleanUpEditorValue() {
                $editor.val($editor.val().match(/^[\d\.]*/)[0]);
            }

            function openDropDown() {
                console.error("openDropDown")
                $unitBox.addClass("open");
                $dropDown
                    .show()
                    .position({
                        my: "left top",
                        at: "left bottom",
                        of: $unitBox,
                        collision: "flip",
                        using: function (calculatedPosition, info) {
                            if (info.vertical === "top") {
                                $unitBox.removeClass("dropdown-flipped");
                                $(this).removeClass("flipped");
                            } else {
                                $unitBox.addClass("dropdown-flipped");
                                $(this).addClass("flipped");
                            }
                            $(this).css({
                                left: calculatedPosition.left + 'px',
                                top: calculatedPosition.top + 'px'
                            });
                        }
                    })
                    .width($unitBox.width());
                isDropDownOpen = true;
            }

            function closeDropDown() {
                $unitBox.removeClass("open");
                $dropDown.hide();
                isDropDownOpen = false;
            }

            function getNonAutoCompleteEditorValue() {
                console.log($editor[0].selectionStart  +  " - " + $editor[0].selectionEnd);
                if ($editor[0].selectionStart < $editor[0].selectionEnd && $editor.selectionEnd === $editor.val().length) {
                    return $editor.val().substring(0, $editor[0].selectionStart);
                } else {
                    return $editor.val();
                }
            }

            function autoCompleteIfPossible(delay) {
                if (config.autoComplete) {
                    clearTimeout(autoCompleteTimeoutId);

                    var highlightedEntry = listBox.getHighlightedEntry();
                    if (highlightedEntry && !doNoAutoCompleteBecauseBackspaceWasPressed) {
                        var autoCompletingEntryDisplayValue = highlightedEntry[config.inputTextProperty];
                        autoCompleteTimeoutId = setTimeout(function () {
                            var nonSelectedEditorValue = getNonAutoCompleteEditorValue();
                            var queryString = getQueryString();
                            var newEditorValue;
                            if (autoCompletingEntryDisplayValue.toLowerCase().indexOf(queryString.toLowerCase()) === 0) {
                                newEditorValue = nonSelectedEditorValue + autoCompletingEntryDisplayValue.substr(queryString.length);
                            } else {
                                newEditorValue = getNonAutoCompleteEditorValue();
                            }
                            console.log("setting editor value to " + newEditorValue);
                            $editor.val(newEditorValue);
                            setTimeout(function () { // we need this to guarantee that the editor has been updated...
                                $editor[0].setSelectionRange(nonSelectedEditorValue.length, newEditorValue.length);
                            }, 0);
                        }, delay || 0);
                    }
                    doNoAutoCompleteBecauseBackspaceWasPressed = false;
                }
            }

            this.$ = $unitBox;
            $unitBox[0].trivialUnitBox = this;

            function updateEntries(newEntries) {
                entries = newEntries;
                $spinners.remove();
                $spinners = $();
                listBox.updateEntries(newEntries);
            }

            this.updateEntries = updateEntries;
            this.getSelectedEntry = function () {
                if (selectedEntry == null && (!config.allowFreeText || !$editor.val())) {
                    return null;
                } else if (selectedEntry == null && config.allowFreeText) {
                    var fakeEntry = $.extend({}, config.freeTextEntryValues);
                    fakeEntry[config.inputTextProperty] = $editor.val();
                    return fakeEntry;
                } else {
                    var selectedEntryToReturn = jQuery.extend({}, selectedEntry);
                    selectedEntryToReturn._trEntryElement = undefined;
                    return selectedEntryToReturn;
                }
            };
            this.selectEntry = selectEntry;
        }

        TrivialComponents.registerJqueryPlugin(TrivialUnitBox, "TrivialUnitBox", "tr-unitbox");

        return $.fn.TrivialUnitBox;
    })
);<commit_msg>trivial-unitbox: fixed many usability problems<commit_after>/*
 Trivial Components (https://github.com/trivial-components/trivial-components)

 Copyright 2015 Yann Massard (https://github.com/yamass) and other contributors

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
(function (factory) {
        "use strict";

        if (typeof define === 'function' && define.amd) {
            // Define as an AMD module if possible
            define('trivial-unitbox', ['trivial-core', 'jquery', 'mustache'], factory);
        } else if (typeof exports === 'object') {
            // Node/CommonJS
            module.exports = factory(require('trivial-core'), require('jquery'), require('mustache'));
        } else if (jQuery && !jQuery.fn.trivialunitbox) {
            // Define using browser globals otherwise
            // Prevent multiple instantiations if the script is loaded twice
            factory(TrivialComponents, jQuery, Mustache);
        }
    }(function (TrivialComponents, $, Mustache) {

        var keyCodes = TrivialComponents.keyCodes;

        function TrivialUnitBox(originalInput, options) {
            options = options || {};
            var config = $.extend({
                unitValueProperty: null,
                decimalSeparator: '.',
                numberUnitValueSeparatorString: ' ',
                inputTextProperty: 'code',
                template: TrivialComponents.currency2LineTemplate,
                selectedEntryTemplate: options.template || TrivialComponents.currencySingleLineShortTemplate,
                selectedEntry: undefined,
                spinnerTemplate: TrivialComponents.defaultSpinnerTemplate,
                noEntriesTemplate: TrivialComponents.defaultNoEntriesTemplate,
                entries: null,
                emptyEntry: {},
                queryFunction: null, // defined below...
                autoComplete: false,
                autoCompleteDelay: 0,
                showTrigger: true,
                matchingOptions: {
                    matchingMode: 'prefix-word',
                    ignoreCase: true,
                    maxLevenshteinDistance: 2
                }
            }, options);

            config.queryFunction = config.queryFunction || TrivialComponents.defaultListQueryFunctionFactory(config.entries || [], config.matchingOptions);

            var listBox;
            var isDropDownOpen = false;
            var entries = config.entries;
            var selectedEntry = null;
            var blurCausedByClickInsideComponent = false;
            var autoCompleteTimeoutId = -1;
            var doNoAutoCompleteBecauseBackspaceWasPressed = false;

            var $spinners = $();
            var $originalInput = $(originalInput);
            var $unitBox = $('
').insertAfter($originalInput);
            var $selectedEntryAndTriggerWrapper = $('
').appendTo($unitBox);
            var $selectedEntryWrapper = $('
').appendTo($selectedEntryAndTriggerWrapper);
            if (config.showTrigger) {
                var $trigger = $('

').appendTo($selectedEntryAndTriggerWrapper);
            }
            $selectedEntryAndTriggerWrapper.mousedown(function () {
                if (isDropDownOpen) {
                    closeDropDown();
                } else {
                    setTimeout(function () { // TODO remove this when Chrome bug is fixed. Chrome scrolls to the top of the page if we do this synchronously. Maybe this has something to do with https://code.google.com/p/chromium/issues/detail?id=342307 .
                        openDropDown();
                        query();
                    });
                }
                $editor.focus();
            });
            var $dropDown = $('

').appendTo("body");
            var $editor;
            if (config.valueProperty) {
                $originalInput.addClass("tr-original-input");
                $editor = $('<input type="text"/>');
            } else {
                $editor = $originalInput;
            }

            $editor.prependTo($unitBox).addClass("tr-unitbox-edit-input")
                .focus(function () {
                    if (blurCausedByClickInsideComponent) {
                        // do nothing!
                    } else {
                        $unitBox.addClass('focus');
                    }
                })
                .blur(function () {
                    if (blurCausedByClickInsideComponent) {
                        $editor.focus();
                    } else {
                        $unitBox.removeClass('focus');
                        cleanUpEditorValue();
                        closeDropDown();
                    }
                })
                .keydown(function (e) {
                    if (e.which == keyCodes.tab || TrivialComponents.isModifierKey(e)) {
                        return; // tab or modifier key was pressed...
                    } else if (e.which == keyCodes.left_arrow || e.which == keyCodes.right_arrow) {
                        return; // let the user navigate freely left and right...
                    }

                    if (e.which == keyCodes.backspace || e.which == keyCodes.delete) {
                        console.log("backspace or delete");
                        doNoAutoCompleteBecauseBackspaceWasPressed = true; // we want query results, but no autocomplete
                    }

                    if (e.which == keyCodes.up_arrow || e.which == keyCodes.down_arrow) {
                        var direction = e.which == keyCodes.up_arrow ? -1 : 1;
                        if (isDropDownOpen) {
                            listBox.highlightNextEntry(direction);
                            autoCompleteIfPossible(config.autoCompleteDelay);
                        } else {
                            openDropDown();
                            query(direction);
                        }
                        return false; // some browsers move the caret to the beginning on up key
                    } else if (isDropDownOpen && e.which == keyCodes.enter) {
                        selectEntry(listBox.getHighlightedEntry());
                        closeDropDown();
                    } else if (e.which == keyCodes.escape) {
                        closeDropDown();
                        cleanUpEditorValue();
                    }
                })
                .keypress(function (e) {
                    var character = String.fromCharCode(e.which);
                    if (character >= '0' && character <= '9'
                        || character === config.decimalSeparator
                        || character === ' ') {
                        // was number input...
                    } else if (e.which != keyCodes.enter) {
                        //console.log("opening because '" + character + "', which: " + e.which);
                        //openDropDown();
                        //query(1);
                    }
                })
                .keyup(function (e) {
                    if (keyCodes.specialKeys.indexOf(e.which) != -1
                        && e.which != keyCodes.backspace
                        && e.which != keyCodes.delete) {
                        // ignore
                    } else if (getQueryString().length > 0) {
                        openDropDown();
                        query(1);
                    } else {
                        closeDropDown();
                    }
                })
                .mousedown(function () {
                    openDropDown();
                    if (entries == null) {
                        query();
                    }
                });

            $unitBox.add($dropDown).mousedown(function () {
                if ($editor.is(":focus")) {
                    console.log("mousedown blurCausedByClickInsideComponent");
                    blurCausedByClickInsideComponent = true;
                }
            }).mouseup(function () {
                if (blurCausedByClickInsideComponent) {
                    $editor.focus();
                    console.log("mouseup # blurCausedByClickInsideComponent");
                    blurCausedByClickInsideComponent = false;
                }
            }).mouseout(function () {
                if (blurCausedByClickInsideComponent) {
                    $editor.focus();
                    console.log("mouseout # blurCausedByClickInsideComponent");
                    blurCausedByClickInsideComponent = false;
                }
            });

            listBox = $dropDown.TrivialListBox(config);
            listBox.$.change(function () {
                var selectedListBoxEntry = listBox.getSelectedEntry();
                if (selectedListBoxEntry) {
                    selectEntry(selectedListBoxEntry);
                    listBox.selectEntry(null);
                    closeDropDown();
                }
            });

            selectEntry(config.selectedEntry || null);

            var getQueryString = function () {
                var nonSelectedEditorValue = getNonAutoCompleteEditorValue();
                var firstQueryCharacterIndex = nonSelectedEditorValue.search(new RegExp('[^\\d\\' + config.decimalSeparator + ' ]'));
                if (firstQueryCharacterIndex != -1) {
                    return nonSelectedEditorValue.substr(firstQueryCharacterIndex);
                } else {
                    return "";
                }
            };

            function query(highlightDirection) {
                var $spinner = $(config.spinnerTemplate).appendTo($dropDown);
                $spinners = $spinners.add($spinner);

                // call queryFunction asynchronously to be sure the input field has been updated before the result callback is called. Note: the query() method is called on keydown...
                setTimeout(function () {
                    config.queryFunction(getQueryString(), function (newEntries) {
                        updateEntries(newEntries);

                        var queryString = getQueryString();
                        if (queryString.length > 0) {
                            listBox.highlightTextMatches(queryString);
                            listBox.highlightNextMatchingEntry(highlightDirection);
                        } else {
                            listBox.highlightNextEntry(highlightDirection);
                        }

                        autoCompleteIfPossible(config.autoCompleteDelay);

                        if (isDropDownOpen) {
                            openDropDown(); // only for repositioning!
                        }
                    });
                });
            }

            function fireChangeEvents() {
                $originalInput.trigger("change");
                $unitBox.trigger("change");
            }

            function selectEntry(entry) {
                if (entry == null) {
                    selectedEntry = null;
                    var $selectedEntry = $(Mustache.render(config.selectedEntryTemplate, config.emptyEntry))
                        .addClass("tr-combobox-entry")
                        .addClass("empty");
                    $selectedEntryWrapper.empty().append($selectedEntry);
                } else {
                    selectedEntry = entry;
                    var $selectedEntry = $(Mustache.render(config.selectedEntryTemplate, entry))
                        .addClass("tr-combobox-entry");
                    $selectedEntryWrapper.empty().append($selectedEntry);
                }
                cleanUpEditorValue();
                fireChangeEvents();
            }

            function isEntrySelected() {
                return selectedEntry != null && selectedEntry !== config.emptyEntry;
            }

            function cleanUpEditorValue() {
                $editor.val($editor.val().match(/^[\d\.]*/)[0]);
            }

            function openDropDown() {
                console.error("openDropDown")
                $unitBox.addClass("open");
                $dropDown
                    .show()
                    .position({
                        my: "left top",
                        at: "left bottom",
                        of: $unitBox,
                        collision: "flip",
                        using: function (calculatedPosition, info) {
                            if (info.vertical === "top") {
                                $unitBox.removeClass("dropdown-flipped");
                                $(this).removeClass("flipped");
                            } else {
                                $unitBox.addClass("dropdown-flipped");
                                $(this).addClass("flipped");
                            }
                            $(this).css({
                                left: calculatedPosition.left + 'px',
                                top: calculatedPosition.top + 'px'
                            });
                        }
                    })
                    .width($unitBox.width());
                isDropDownOpen = true;
            }

            function closeDropDown() {
                $unitBox.removeClass("open");
                $dropDown.hide();
                isDropDownOpen = false;
            }

            function getNonAutoCompleteEditorValue() {
                console.log($editor[0].selectionStart  +  " - " + $editor[0].selectionEnd);
                if ($editor[0].selectionStart < $editor[0].selectionEnd && $editor.selectionEnd === $editor.val().length) {
                    return $editor.val().substring(0, $editor[0].selectionStart);
                } else {
                    return $editor.val();
                }
            }

            function autoCompleteIfPossible(delay) {
                if (config.autoComplete) {
                    clearTimeout(autoCompleteTimeoutId);

                    var highlightedEntry = listBox.getHighlightedEntry();
                    if (highlightedEntry && !doNoAutoCompleteBecauseBackspaceWasPressed) {
                        var autoCompletingEntryDisplayValue = highlightedEntry[config.inputTextProperty];
                        autoCompleteTimeoutId = setTimeout(function () {
                            var nonSelectedEditorValue = getNonAutoCompleteEditorValue();
                            var queryString = getQueryString();
                            var newEditorValue;
                            if (autoCompletingEntryDisplayValue.toLowerCase().indexOf(queryString.toLowerCase()) === 0) {
                                newEditorValue = nonSelectedEditorValue + autoCompletingEntryDisplayValue.substr(queryString.length);
                            } else {
                                newEditorValue = getNonAutoCompleteEditorValue();
                            }
                            console.log("setting editor value to " + newEditorValue);
                            $editor.val(newEditorValue);
                            setTimeout(function () { // we need this to guarantee that the editor has been updated...
                                $editor[0].setSelectionRange(nonSelectedEditorValue.length, newEditorValue.length);
                            }, 0);
                        }, delay || 0);
                    }
                    doNoAutoCompleteBecauseBackspaceWasPressed = false;
                }
            }

            this.$ = $unitBox;
            $unitBox[0].trivialUnitBox = this;

            function updateEntries(newEntries) {
                entries = newEntries;
                $spinners.remove();
                $spinners = $();
                listBox.updateEntries(newEntries);
            }

            this.updateEntries = updateEntries;
            this.getSelectedEntry = function () {
                if (selectedEntry == null && (!config.allowFreeText || !$editor.val())) {
                    return null;
                } else if (selectedEntry == null && config.allowFreeText) {
                    var fakeEntry = $.extend({}, config.freeTextEntryValues);
                    fakeEntry[config.inputTextProperty] = $editor.val();
                    return fakeEntry;
                } else {
                    var selectedEntryToReturn = jQuery.extend({}, selectedEntry);
                    selectedEntryToReturn._trEntryElement = undefined;
                    return selectedEntryToReturn;
                }
            };
            this.selectEntry = selectEntry;
        }

        TrivialComponents.registerJqueryPlugin(TrivialUnitBox, "TrivialUnitBox", "tr-unitbox");

        return $.fn.TrivialUnitBox;
    })
);<|endoftext|>


<commit_before>// Utility for creating objects in older browsers
if ( typeof Object.create !== 'function' )
{
  Object.create = function( obj )
  {
    function F() {}
    F.prototype = obj;
    return new F();
  };
}

/*!
 * jQuery panelSnap
 * Version 0.3.0
 *
 * Requires:
 * - jQuery 1.7.1 or higher (Works with the API changes from 1.9.1 too)
 * - jQuery scrollEvents.js (included in the package)
 *
 * https://github.com/guidobouman/jquery-panelsnap
 *
 * Copyright 2013, Guido Bouman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Date: Wed Feb 13 16:05:00 2013 +0100
 */
(function($, window, document, undefined)
{
  var pluginName = 'panelSnap';
  var storageName = 'plugin_' + pluginName;

  var pluginObject = {
    isMouseDown: false,
    isSnapping: false,
    scrollOffset: 0,

    init: function(options, container)
    {
      var self = this;

      self.$window = $(window);
      self.$document = $(document);

      self.container = container;
      self.$container = $(container);

      self.options = $.extend(true, {}, $.fn.panelSnap.options, options);

      self.bind();

      return self;
    },

    bind: function()
    {
      var self = this;

      self.bindProxied(self.$document, 'scrollstop', self.processScroll);
      self.bindProxied(self.$document, 'scrollstart', self.initScroll);
      self.bindProxied(self.$document, 'mousewheel', self.holdScroll);
      self.bindProxied(self.$document, 'mousedown', self.mouseDown);
      self.bindProxied(self.$document, 'mouseup', self.mouseUp);
      self.bindProxied(self.$window, 'resize', self.processScroll);

      if(self.options.$menu !== false)
      {
        self.bindProxied($('a', self.options.$menu), 'click', self.captureMenuClick);
      }
    },

    bindProxied: function($element, event, method)
    {
      var self = this;

      $element.on(event + self.options.namespace, $.proxy(function(e)
      {
        return method.call(self, e);
      }, self));
    },

    destroy: function()
    {
      var self = this;

      // Gotta love namespaced events!
      self.$document.off(self.options.namespace);
      self.$window.off(self.options.namespace);

      if(self.options.$menu !== false)
      {
        $('a', self.options.$menu).off(self.options.namespace);
      }

      self.$container.removeData(storageName);
    },

    captureMenuClick: function(e)
    {
      var self = this;

      var $target = $(self.options.panelSelector + '.' + $(e.currentTarget).data('panel'), self.$container);

      self.snapToPanel($target);

      return false;
    },

    holdScroll: function(e)
    {
      var self = this;

      self.$container.stop(true);
      self.isSnapping = false;
    },

    initScroll: function(e)
    {
      var self = this;

      // Deprecated, moved storage of scrollOffset to callback of panelSnap
      // self.scrollOffset = self.$container.scrollTop();
    },

    processScroll: function(e)
    {
      var self = this;

      if(self.isMouseDown)
      {
        self.$container.one('mouseup', self.processScroll);
        return;
      }

      if(self.isSnapping)
      {
        return;
      }

      var interval = self.$container.height();
      var offset = self.$container.scrollTop();
      var scrollDifference = offset - self.scrollOffset;
      var maxOffset = self.$container[0].scrollHeight - interval;

      if(
        scrollDifference === 0 ||
        offset < 0 ||
        offset > maxOffset
      )
      {
        return;
      }

      var child_number;
      if(scrollDifference < -self.options.directionThreshold && scrollDifference > -interval)
      {
        child_number = Math.floor(offset / interval);
      }
      else if(scrollDifference > self.options.directionThreshold && scrollDifference < interval)
      {
        child_number = Math.ceil(offset / interval);
      }
      else
      {
        child_number = Math.round(offset / interval);
      }

      var target_class = $(self.options.panelSelector, self.$container)[child_number].className;
      var $target = $(self.options.panelSelector + '.' + target_class, self.$container);

      self.snapToPanel($target);
    },

    mouseDown: function(e)
    {
      var self = this;

      self.isMouseDown = true;
    },

    mouseUp: function(e)
    {
      var self = this;

      self.isMouseDown = false;
    },

    snapToPanel: function($target)
    {
      var self = this;

      self.isSnapping = true;

      self.options.onSnapStart.call(self, $target);

      var scrollTarget = $target.offset().top;

      self.$container.animate(
      {
        scrollTop: scrollTarget
      }, self.options.slideSpeed, function()
      {
        self.scrollOffset = scrollTarget;
        self.isSnapping = false;

        // Call callback
        self.options.onSnapFinish.call(self, $target);
      });

      if(self.options.$menu !== false)
      {
        $('a.active', self.options.$menu).removeClass('active');
        var $activeItem = $('a[data-panel=' + $target.attr('class') + ']', self.options.$menu);
        $activeItem.addClass('active');
      }
    }
  };

  $.fn[pluginName] = function(options)
  {
    return this.each(function()
    {
      var pluginInstance = $.data(this, storageName);
      if(typeof options === 'object' || options === 'init' || ! options)
      {
        if(!pluginInstance)
        {
          if(options === 'init')
          {
            options = Array.prototype.slice.call(arguments, 1);
          }

          pluginInstance = $.data(this, storageName, Object.create(pluginObject).init(options, this));
        }
        else
        {
          $.error('Plugin is already initialized for this object.');
          return;
        }
      }
      else if(!pluginInstance)
      {
        $.error('Plugin is not initialized for this object yet.');
        return;
      }
      else if(pluginInstance[options])
      {
        method = options;
        options = Array.prototype.slice.call(arguments, 1);
        pluginInstance[method](options);
      }
      else
      {
        $.error('Method ' +  options + ' does not exist on jQuery.panelSnap.');
        return;
      }
    });
  };

  $.fn.panelSnap.options = {
    $menu: false,
    panelSelector: 'section',
    namespace: '.panelSnap',
    onSnapStart: function(){},
    onSnapFinish: function(){},
    directionThreshold: 50,
    slideSpeed: 200
  };

})(jQuery, window, document);<commit_msg>Makes plugin comply to plugin boilerplate rules defaults.<commit_after>// Utility for creating objects in older browsers
if ( typeof Object.create !== 'function' )
{
  Object.create = function( obj )
  {
    function F() {}
    F.prototype = obj;
    return new F();
  };
}

/*!
 * jQuery panelSnap
 * Version 0.3.0
 *
 * Requires:
 * - jQuery 1.7.1 or higher (Works with the API changes from 1.9.1 too)
 * - jQuery scrollEvents.js (included in the package)
 *
 * https://github.com/guidobouman/jquery-panelsnap
 *
 * Copyright 2013, Guido Bouman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Date: Wed Feb 13 16:05:00 2013 +0100
 */
(function($, window, document, undefined)
{
  var pluginName = 'panelSnap';
  var storageName = 'plugin_' + pluginName;

  var pluginObject = {
    isMouseDown: false,
    isSnapping: false,
    scrollOffset: 0,

    init: function(options, container)
    {
      var self = this;

      self.$window = $(window);
      self.$document = $(document);

      self.container = container;
      self.$container = $(container);

      self.options = $.extend(true, {}, $.fn[pluginName].options, options);

      self.bind();

      return self;
    },

    bind: function()
    {
      var self = this;

      self.bindProxied(self.$document, 'scrollstop', self.processScroll);
      self.bindProxied(self.$document, 'scrollstart', self.initScroll);
      self.bindProxied(self.$document, 'mousewheel', self.holdScroll);
      self.bindProxied(self.$document, 'mousedown', self.mouseDown);
      self.bindProxied(self.$document, 'mouseup', self.mouseUp);
      self.bindProxied(self.$window, 'resize', self.processScroll);

      if(self.options.$menu !== false)
      {
        self.bindProxied($('a', self.options.$menu), 'click', self.captureMenuClick);
      }
    },

    bindProxied: function($element, event, method)
    {
      var self = this;

      $element.on(event + self.options.namespace, $.proxy(function(e)
      {
        return method.call(self, e);
      }, self));
    },

    destroy: function()
    {
      var self = this;

      // Gotta love namespaced events!
      self.$document.off(self.options.namespace);
      self.$window.off(self.options.namespace);

      if(self.options.$menu !== false)
      {
        $('a', self.options.$menu).off(self.options.namespace);
      }

      self.$container.removeData(storageName);
    },

    captureMenuClick: function(e)
    {
      var self = this;

      var $target = $(self.options.panelSelector + '.' + $(e.currentTarget).data('panel'), self.$container);

      self.snapToPanel($target);

      return false;
    },

    holdScroll: function(e)
    {
      var self = this;

      self.$container.stop(true);
      self.isSnapping = false;
    },

    initScroll: function(e)
    {
      var self = this;

      // Deprecated, moved storage of scrollOffset to callback of panelSnap
      // self.scrollOffset = self.$container.scrollTop();
    },

    processScroll: function(e)
    {
      var self = this;

      if(self.isMouseDown)
      {
        self.$container.one('mouseup', self.processScroll);
        return;
      }

      if(self.isSnapping)
      {
        return;
      }

      var interval = self.$container.height();
      var offset = self.$container.scrollTop();
      var scrollDifference = offset - self.scrollOffset;
      var maxOffset = self.$container[0].scrollHeight - interval;

      if(
        scrollDifference === 0 ||
        offset < 0 ||
        offset > maxOffset
      )
      {
        return;
      }

      var child_number;
      if(scrollDifference < -self.options.directionThreshold && scrollDifference > -interval)
      {
        child_number = Math.floor(offset / interval);
      }
      else if(scrollDifference > self.options.directionThreshold && scrollDifference < interval)
      {
        child_number = Math.ceil(offset / interval);
      }
      else
      {
        child_number = Math.round(offset / interval);
      }

      var target_class = $(self.options.panelSelector, self.$container)[child_number].className;
      var $target = $(self.options.panelSelector + '.' + target_class, self.$container);

      self.snapToPanel($target);
    },

    mouseDown: function(e)
    {
      var self = this;

      self.isMouseDown = true;
    },

    mouseUp: function(e)
    {
      var self = this;

      self.isMouseDown = false;
    },

    snapToPanel: function($target)
    {
      var self = this;

      self.isSnapping = true;

      self.options.onSnapStart.call(self, $target);

      var scrollTarget = $target.offset().top;

      self.$container.animate(
      {
        scrollTop: scrollTarget
      }, self.options.slideSpeed, function()
      {
        self.scrollOffset = scrollTarget;
        self.isSnapping = false;

        // Call callback
        self.options.onSnapFinish.call(self, $target);
      });

      if(self.options.$menu !== false)
      {
        $('a.active', self.options.$menu).removeClass('active');
        var $activeItem = $('a[data-panel=' + $target.attr('class') + ']', self.options.$menu);
        $activeItem.addClass('active');
      }
    }
  };

  $.fn[pluginName] = function(options)
  {
    return this.each(function()
    {
      var pluginInstance = $.data(this, storageName);
      if(typeof options === 'object' || options === 'init' || ! options)
      {
        if(!pluginInstance)
        {
          if(options === 'init')
          {
            options = Array.prototype.slice.call(arguments, 1);
          }

          pluginInstance = $.data(this, storageName, Object.create(pluginObject).init(options, this));
        }
        else
        {
          $.error('Plugin is already initialized for this object.');
          return;
        }
      }
      else if(!pluginInstance)
      {
        $.error('Plugin is not initialized for this object yet.');
        return;
      }
      else if(pluginInstance[options])
      {
        method = options;
        options = Array.prototype.slice.call(arguments, 1);
        pluginInstance[method](options);
      }
      else
      {
        $.error('Method ' +  options + ' does not exist on jQuery.' + pluginName + '.');
        return;
      }
    });
  };

  $.fn[pluginName].options = {
    $menu: false,
    panelSelector: 'section',
    namespace: '.panelSnap',
    onSnapStart: function(){},
    onSnapFinish: function(){},
    directionThreshold: 50,
    slideSpeed: 200
  };

})(jQuery, window, document);<|endoftext|>


<commit_before>// Check SCSS for code quality
module.exports = function(grunt) {
    grunt.config('scsslint', {
        options: {
            bundleExec: false,
            colorizeOutput: true,
            config: '.scss-lint.yml',
            exclude: [
                'scss/core/_normalize.scss',
                'scss/iconfont/*',
                'scss/main/_oldie.scss',
                'scss/mixins/_type.scss',
                'scss/mixins/_units.scss',
                'scss/modules/_forms.scss',
                'scss/modules/_images.scss'
            ],
            reporterOutput: null
        },
        all: [
            'scss/**/*.scss'
        ]
    });

    grunt.loadNpmTasks('grunt-scss-lint');
};
<commit_msg>Add compact view for scss-lint output<commit_after>// Check SCSS for code quality
module.exports = function(grunt) {
    grunt.config('scsslint', {
        options: {
            bundleExec: false,
            colorizeOutput: true,
            compact: true,
            config: '.scss-lint.yml',
            exclude: [
                'scss/core/_normalize.scss',
                'scss/iconfont/*',
                'scss/main/_oldie.scss',
                'scss/mixins/_type.scss',
                'scss/mixins/_units.scss',
                'scss/modules/_forms.scss',
                'scss/modules/_images.scss'
            ],
            reporterOutput: null
        },
        all: [
            'scss/**/*.scss'
        ]
    });

    grunt.loadNpmTasks('grunt-scss-lint');
};
<|endoftext|>


<commit_before>/*!
 * jQuery-Seat-Charts v1.1.4
 * https://github.com/mateuszmarkowski/jQuery-Seat-Charts
 *
 * Copyright 2013, 2016 Mateusz Markowski
 * Released under the MIT license
 */

!function(t){t.fn.seatCharts=function(s){if(this.data("seatCharts"))return this.data("seatCharts");var e=this,a={},n=[],i={animate:!1,naming:{top:!0,left:!0,getId:function(t,s,e){return s+"_"+e},getLabel:function(t,s,e){return e}},legend:{node:null,items:[]},click:function(){return"available"==this.status()?"selected":"selected"==this.status()?"available":this.style()},focus:function(){return"available"==this.status()?"focused":this.style()},blur:function(){return this.status()},seats:{}},r=function(s,e){return function(n){var i=this;i.settings=t.extend({status:"available",style:"available",data:e.seats[n.character]||{}},n),i.settings.$node=t("

"),i.settings.$node.attr({id:i.settings.id,role:"checkbox","aria-checked":!1,focusable:!0,tabIndex:-1}).text(i.settings.label).addClass(["seatCharts-seat","seatCharts-cell","available"].concat(i.settings.classes,"undefined"==typeof e.seats[i.settings.character]?[]:e.seats[i.settings.character].classes).join(" ")),i.data=function(){return i.settings.data},i["char"]=function(){return i.settings.character},i.node=function(){return i.settings.$node},i.style=function(){return 1==arguments.length?function(t){var s=i.settings.style;return t==s?s:(i.settings.status="focused"!=t?t:i.settings.status,i.settings.$node.attr("aria-checked","selected"==t),e.animate?i.settings.$node.switchClass(s,t,200):i.settings.$node.removeClass(s).addClass(t),i.settings.style=t)}(arguments[0]):i.settings.style},i.status=function(){return i.settings.status=1==arguments.length?i.style(arguments[0]):i.settings.status},function(n,r,c){t.each(["click","focus","blur"],function(t,u){i[u]=function(){return"focus"==u&&(void 0!==s.attr("aria-activedescendant")&&a[s.attr("aria-activedescendant")].blur(),s.attr("aria-activedescendant",c.settings.id),c.node().focus()),i.style("function"==typeof n[r][u]?n[r][u].apply(c):e[u].apply(c))}})}(e.seats,i.settings.character,i),i.node().on("click",i.click).on("mouseenter",i.focus).on("mouseleave",i.blur).on("keydown",function(t,e){return function(n){var i;switch(n.which){case 32:n.preventDefault(),t.click();break;case 40:case 38:if(n.preventDefault(),i=function r(t,s,a){var c;return c=t.index(a)||38!=n.which?t.index(a)==t.length-1&&40==n.which?t.first():t.eq(t.index(a)+(38==n.which?-1:1)):t.last(),i=c.find(".seatCharts-seat,.seatCharts-space").eq(s.index(e)),i.hasClass("seatCharts-space")?r(t,s,c):i}(e.parents(".seatCharts-container").find(".seatCharts-row:not(.seatCharts-header)"),e.parents(".seatCharts-row:first").find(".seatCharts-seat,.seatCharts-space"),e.parents(".seatCharts-row:not(.seatCharts-header)")),!i.length)return;t.blur(),a[i.attr("id")].focus(),i.focus(),s.attr("aria-activedescendant",i.attr("id"));break;case 37:case 39:if(n.preventDefault(),i=function(t){return t.index(e)||37!=n.which?t.index(e)==t.length-1&&39==n.which?t.first():t.eq(t.index(e)+(37==n.which?-1:1)):t.last()}(e.parents(".seatCharts-container:first").find(".seatCharts-seat:not(.seatCharts-space)")),!i.length)return;t.blur(),a[i.attr("id")].focus(),i.focus(),s.attr("aria-activedescendant",i.attr("id"))}}}(i,i.node()))}}(e,i);if(e.addClass("seatCharts-container"),t.extend(!0,i,s),i.naming.rows=i.naming.rows||function(t){for(var s=[],e=1;t>=e;e++)s.push(e);return s}(i.map.length),i.naming.columns=i.naming.columns||function(t){for(var s=[],e=1;t>=e;e++)s.push(e);return s}(i.map[0].split("").length),i.naming.top){var c=t("

").addClass("seatCharts-row seatCharts-header");i.naming.left&&c.append(t("

").addClass("seatCharts-cell")),t.each(i.naming.columns,function(s,e){c.append(t("

").addClass("seatCharts-cell").text(e))})}return e.append(c),t.each(i.map,function(s,c){var u=t("

").addClass("seatCharts-row");i.naming.left&&u.append(t("

").addClass("seatCharts-cell seatCharts-space").text(i.naming.rows[s])),t.each(c.match(/[a-z_]{1}(\[[0-9a-z_]{0,}(,[0-9a-z_ ]+)?\])?/gi),function(e,c){var h=c.match(/([a-z_]{1})(\[([0-9a-z_ ,]+)\])?/i),d=h[1],o="undefined"!=typeof h[3]?h[3].split(","):[],l=o.length?o[0]:null,f=2===o.length?o[1]:null;u.append("_"!=d?function(t){i.seats[d]=d in i.seats?i.seats[d]:{};var c=l?l:t.getId(d,t.rows[s],t.columns[e]);return a[c]=new r({id:c,label:f?f:t.getLabel(d,t.rows[s],t.columns[e]),row:s,column:e,character:d}),n.push(c),a[c].node()}(i.naming):t("

").addClass("seatCharts-cell seatCharts-space"))}),e.append(u)}),i.legend.items.length?function(s){var a=(s.node||t("
</div").insertAfter(e)).addClass("seatCharts-legend"),n=t("

").addClass("seatCharts-legendList").appendTo(a);return t.each(s.items,function(s,e){n.append(t("

").addClass("seatCharts-legendItem").append(t("

").addClass(["seatCharts-seat","seatCharts-cell",e[1]].concat(i.classes,"undefined"==typeof i.seats[e[0]]?[]:i.seats[e[0]].classes).join(" "))).append(t("").addClass("seatCharts-legendDescription").text(e[2])))}),a}(i.legend):null,e.attr({tabIndex:0}),e.focus(function(){e.attr("aria-activedescendant")&&a[e.attr("aria-activedescendant")].blur(),e.find(".seatCharts-seat:not(.seatCharts-space):first").focus(),a[n[0]].focus()}),e.data("seatCharts",{seats:a,seatIds:n,status:function(){var s=this;return 1==arguments.length?s.seats[arguments[0]].status():function(e,a){return"string"==typeof e?s.seats[e].status(a):function(){t.each(e,function(t,e){s.seats[e].status(a)})}()}(arguments[0],arguments[1])},each:function(t){var s=this;for(var e in s.seats)if(!1===t.call(s.seats[e],e))return e;return!0},node:function(){var s=this;return t("#"+s.seatIds.join(",#"))},find:function(t){var s=this,e=s.set();return t instanceof RegExp?function(){return s.each(function(s){s.match(t)&&e.push(s,this)}),e}():1==t.length?function(t){return s.each(function(){this["char"]()==t&&e.push(this.settings.id,this)}),e}(t):function(){return t.indexOf(".")>-1?function(){var a=t.split(".");return s.each(function(t){this["char"]()==a[0]&&this.status()==a[1]&&e.push(this.settings.id,this)}),e}():function(){return s.each(function(){this.status()==t&&e.push(this.settings.id,this)}),e}()}()},set:function u(){var s=this;return{seats:[],seatIds:[],length:0,status:function(){var s=arguments,e=this;return 1==this.length&&0==s.length?this.seats[0].status():function(){t.each(e.seats,function(){this.status.apply(this,s)})}()},node:function(){return s.node.call(this)},each:function(){return s.each.call(this,arguments[0])},get:function(){return s.get.call(this,arguments[0])},find:function(){return s.find.call(this,arguments[0])},set:function(){return u.call(s)},push:function(t,s){this.seats.push(s),this.seatIds.push(t),++this.length}}},get:function(s){var e=this;return"string"==typeof s?e.seats[s]:function(){var a=e.set();return t.each(s,function(t,s){"object"==typeof e.seats[s]&&a.push(s,e.seats[s])}),a}()}}),e.data("seatCharts")}}(jQuery);<commit_msg>updated minified version<commit_after>/*!
 * jQuery-Seat-Charts v1.1.4
 * https://github.com/mateuszmarkowski/jQuery-Seat-Charts
 *
 * Copyright 2013, 2016 Mateusz Markowski
 * Released under the MIT license
 */

!function(t){t.fn.seatCharts=function(s){if(this.data("seatCharts"))return this.data("seatCharts");var e=this,a={},n=[],i={animate:!1,naming:{top:!0,left:!0,getId:function(t,s,e){return s+"_"+e},getLabel:function(t,s,e){return e}},legend:{node:null,items:[]},click:function(){return"available"==this.status()?"selected":"selected"==this.status()?"available":this.style()},focus:function(){return"available"==this.status()?"focused":this.style()},blur:function(){return this.status()},seats:{}},r=function(s,e){return function(n){var i=this;i.settings=t.extend({status:"available",style:"available",data:e.seats[n.character]||{}},n),i.settings.$node=t("

"),i.settings.$node.attr({id:i.settings.id,role:"checkbox","aria-checked":!1,focusable:!0,tabIndex:-1}).text(i.settings.label).addClass(["seatCharts-seat","seatCharts-cell","available"].concat(i.settings.classes,"undefined"==typeof e.seats[i.settings.character]?[]:e.seats[i.settings.character].classes).join(" ")),i.data=function(){return i.settings.data},i["char"]=function(){return i.settings.character},i.node=function(){return i.settings.$node},i.style=function(){return 1==arguments.length?function(t){var s=i.settings.style;return t==s?s:(i.settings.status="focused"!=t?t:i.settings.status,i.settings.$node.attr("aria-checked","selected"==t),e.animate?i.settings.$node.switchClass(s,t,200):i.settings.$node.removeClass(s).addClass(t),i.settings.style=t)}(arguments[0]):i.settings.style},i.status=function(){return i.settings.status=1==arguments.length?i.style(arguments[0]):i.settings.status},function(n,r,c){t.each(["click","focus","blur"],function(t,u){i[u]=function(){return"focus"==u&&(void 0!==s.attr("aria-activedescendant")&&a[s.attr("aria-activedescendant")].blur(),s.attr("aria-activedescendant",c.settings.id),c.node().focus()),i.style("function"==typeof n[r][u]?n[r][u].apply(c):e[u].apply(c))}})}(e.seats,i.settings.character,i),i.node().on("click",i.click).on("mouseenter",i.focus).on("mouseleave",i.blur).on("keydown",function(t,e){return function(n){var i;switch(n.which){case 32:n.preventDefault(),t.click();break;case 40:case 38:if(n.preventDefault(),i=function r(t,s,a){var c;return c=t.index(a)||38!=n.which?t.index(a)==t.length-1&&40==n.which?t.first():t.eq(t.index(a)+(38==n.which?-1:1)):t.last(),i=c.find(".seatCharts-seat,.seatCharts-space").eq(s.index(e)),i.hasClass("seatCharts-space")?r(t,s,c):i}(e.parents(".seatCharts-container").find(".seatCharts-row:not(.seatCharts-header)"),e.parents(".seatCharts-row:first").find(".seatCharts-seat,.seatCharts-space"),e.parents(".seatCharts-row:not(.seatCharts-header)")),!i.length)return;t.blur(),a[i.attr("id")].focus(),i.focus(),s.attr("aria-activedescendant",i.attr("id"));break;case 37:case 39:if(n.preventDefault(),i=function(t){return t.index(e)||37!=n.which?t.index(e)==t.length-1&&39==n.which?t.first():t.eq(t.index(e)+(37==n.which?-1:1)):t.last()}(e.parents(".seatCharts-container:first").find(".seatCharts-seat:not(.seatCharts-space)")),!i.length)return;t.blur(),a[i.attr("id")].focus(),i.focus(),s.attr("aria-activedescendant",i.attr("id"))}}}(i,i.node()))}}(e,i);if(e.addClass("seatCharts-container"),t.extend(!0,i,s),i.naming.rows=i.naming.rows||function(t){for(var s=[],e=1;t>=e;e++)s.push(e);return s}(i.map.length),i.naming.columns=i.naming.columns||function(t){for(var s=[],e=1;t>=e;e++)s.push(e);return s}(i.map[0].split("").length),i.naming.top){var c=t("

").addClass("seatCharts-row seatCharts-header");i.naming.left&&c.append(t("

").addClass("seatCharts-cell")),t.each(i.naming.columns,function(s,e){c.append(t("

").addClass("seatCharts-cell").text(e))})}return e.append(c),t.each(i.map,function(s,c){var u=t("

").addClass("seatCharts-row");i.naming.left&&u.append(t("

").addClass("seatCharts-cell seatCharts-space").text(i.naming.rows[s])),t.each(c.match(/[a-z_]{1}(\[[0-9a-z_]{0,}(,[0-9a-z_ ]+)?\])?/gi),function(e,c){var h=c.match(/([a-z_]{1})(\[([0-9a-z_ ,]+)\])?/i),d=h[1],o="undefined"!=typeof h[3]?h[3].split(","):[],l=o.length?o[0]:null,f=2===o.length?o[1]:null;u.append("_"!=d?function(t){i.seats[d]=d in i.seats?i.seats[d]:{};var c=l?l:t.getId(d,t.rows[s],t.columns[e]);return a[c]=new r({id:c,label:f?f:t.getLabel(d,t.rows[s],t.columns[e]),row:s,column:e,character:d}),n.push(c),a[c].node()}(i.naming):t("

").addClass("seatCharts-cell seatCharts-space"))}),e.append(u)}),i.legend.items.length?function(s){var a=(s.node||t("

").insertAfter(e)).addClass("seatCharts-legend"),n=t("

").addClass("seatCharts-legendList").appendTo(a);return t.each(s.items,function(s,e){n.append(t("

").addClass("seatCharts-legendItem").append(t("

").addClass(["seatCharts-seat","seatCharts-cell",e[1]].concat(i.classes,"undefined"==typeof i.seats[e[0]]?[]:i.seats[e[0]].classes).join(" "))).append(t("").addClass("seatCharts-legendDescription").text(e[2])))}),a}(i.legend):null,e.attr({tabIndex:0}),e.focus(function(){e.attr("aria-activedescendant")&&a[e.attr("aria-activedescendant")].blur(),e.find(".seatCharts-seat:not(.seatCharts-space):first").focus(),a[n[0]].focus()}),e.data("seatCharts",{seats:a,seatIds:n,status:function(){var s=this;return 1==arguments.length?s.seats[arguments[0]].status():function(e,a){return"string"==typeof e?s.seats[e].status(a):function(){t.each(e,function(t,e){s.seats[e].status(a)})}()}(arguments[0],arguments[1])},each:function(t){var s=this;for(var e in s.seats)if(!1===t.call(s.seats[e],e))return e;return!0},node:function(){var s=this;return t("#"+s.seatIds.join(",#"))},find:function(t){var s=this,e=s.set();return t instanceof RegExp?function(){return s.each(function(s){s.match(t)&&e.push(s,this)}),e}():1==t.length?function(t){return s.each(function(){this["char"]()==t&&e.push(this.settings.id,this)}),e}(t):function(){return t.indexOf(".")>-1?function(){var a=t.split(".");return s.each(function(t){this["char"]()==a[0]&&this.status()==a[1]&&e.push(this.settings.id,this)}),e}():function(){return s.each(function(){this.status()==t&&e.push(this.settings.id,this)}),e}()}()},set:function u(){var s=this;return{seats:[],seatIds:[],length:0,status:function(){var s=arguments,e=this;return 1==this.length&&0==s.length?this.seats[0].status():function(){t.each(e.seats,function(){this.status.apply(this,s)})}()},node:function(){return s.node.call(this)},each:function(){return s.each.call(this,arguments[0])},get:function(){return s.get.call(this,arguments[0])},find:function(){return s.find.call(this,arguments[0])},set:function(){return u.call(s)},push:function(t,s){this.seats.push(s),this.seatIds.push(t),++this.length}}},get:function(s){var e=this;return"string"==typeof s?e.seats[s]:function(){var a=e.set();return t.each(s,function(t,s){"object"==typeof e.seats[s]&&a.push(s,e.seats[s])}),a}()}}),e.data("seatCharts")}}(jQuery);<|endoftext|>


<commit_before>const { resolve, join } = require('path');

const webpack = require('webpack');
const nsWebpack = require('nativescript-dev-webpack');
const nativescriptTarget = require('nativescript-dev-webpack/nativescript-target');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const { NativeScriptWorkerPlugin } = require('nativescript-worker-loader/NativeScriptWorkerPlugin');

const os = require('os');
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
const dropDownMangleExcludes = require('nativescript-drop-down/uglify-mangle-excludes').default;
const cacheBusterTimestamp = Date.now().toString(36);

module.exports = env => {
  const platform = env && (env.android && 'android' || env.ios && 'ios');
  if ( !platform ) {
    throw new Error('You need to provide a target platform!');
  }
  const platforms = ['ios', 'android'];
  const ngToolsWebpackOptions = { tsConfigPath: 'tsconfig.aot.json' };
  const { snapshot, uglify, report, aot } = env;

  const config = {
    context: resolve('./app'),
    target: nativescriptTarget,
    entry: {
      bundle: aot ? './main.aot.ts' : './main.ts',
      vendor: './vendor',
    },
    output: {
      pathinfo: true,
      // Default destination inside platforms/<platform>/...
      path: resolve(nsWebpack.getAppPath(platform)),
      libraryTarget: 'commonjs2',
      filename: `[name]_${cacheBusterTimestamp}.js`,
      chunkFilename: '[id].[chunkhash].js',
    },
    resolve: {
      extensions: ['.ts', '.js', '.scss', '.css'],
      // Resolve {N} system modules from tns-core-modules
      modules: [
        'node_modules/tns-core-modules',
        'node_modules',
      ],
      alias: {
        '~': resolve('./app')
      },
      // don't resolve symlinks to symlinked modules
      // symlinks: false
    },
    resolveLoader: {
      // don't resolve symlinks to symlinked loaders
      symlinks: false
    },
    node: {
      // Disable node shims that conflict with NativeScript
      'http': false,
      'timers': false,
      'setImmediate': false,
      'fs': 'empty',
    },
    module: {
      rules: [
        { test: /\.html$|\.xml$/, use: 'raw-loader' },

        // tns-core-modules reads the app.css and its imports using css-loader
        { test: /\/app\.css$/, use: 'css-loader?url=false' },
        { test: /\/app\.scss$/, use: ['css-loader?url=false', 'sass-loader'] },

        // Angular components reference css files and their imports using raw-loader
        { test: /\.css$/, exclude: /\/app\.css$/, use: 'raw-loader' },
        { test: /\.scss$/, exclude: /\/app\.scss$/, use: ['raw-loader', 'resolve-url-loader', 'sass-loader'] },

        // Compile TypeScript files with ahead-of-time compiler.
        {
          test: /.ts$/, use: [
            'nativescript-dev-webpack/moduleid-compat-loader',
            { loader: '@ngtools/webpack', options: ngToolsWebpackOptions },
            { loader: 'angular-router-loader?aot=true' }
          ]
        },
        { test: /\.json$/, use: [{ loader: 'json-loader' }] }
      ],
    },
    plugins: [
      // Vendor libs go to the vendor.js chunk
      new webpack.optimize.CommonsChunkPlugin({
        name: ['vendor'],
        filename: `vendor_${cacheBusterTimestamp}.js`
      }),
      // Define useful constants like TNS_WEBPACK
      new webpack.DefinePlugin({
        'global.TNS_WEBPACK': 'true',
      }),
      // Copy assets to out dir. Add your own globs as needed.
      new CopyWebpackPlugin(
        [
          { from: 'App_Resources/**' },
          { from: 'assets/**' },
          { from: 'fonts/**' },
          { from: '**/*.jpg' },
          { from: '**/*.png' },
          { from: '**/*.xml' }
          ],
        // usually used for local json file
        // if testing out wip backend apis
        { ignore: ['assets/json/**'] }
      ),

      // Generate a bundle starter script and activate it in package.json
      new nsWebpack.GenerateBundleStarterPlugin([
        `./vendor_${cacheBusterTimestamp}`,
        `./bundle_${cacheBusterTimestamp}`
      ]),
      // Support for web workers since v3.2
      new NativeScriptWorkerPlugin(),
      // AngularCompilerPlugin with augmented NativeScript filesystem to handle platform specific resource resolution.
      new nsWebpack.NativeScriptAngularCompilerPlugin(
        Object.assign({
          entryModule: resolve(__dirname, 'app/app.module#AppModule'),
          skipCodeGeneration: !aot,
          platformOptions: {
            platform,
            platforms,
            // ignore: ['App_Resources']
          },
        }, ngToolsWebpackOptions)
      ),
      // Does IPC communication with the {N} CLI to notify events when running in watch mode.
      new nsWebpack.WatchStateLoggerPlugin(),
    ],
  };
  if ( report ) {
    // Generate report files for bundles content
    config.plugins.push(new BundleAnalyzerPlugin({
      analyzerMode: 'static',
      openAnalyzer: false,
      generateStatsFile: true,
      reportFilename: join(__dirname, 'report', `report.html`),
      statsFilename: join(__dirname, 'report', `stats.json`),
    }));
  }
  if ( snapshot ) {
    config.plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({
      chunk: 'vendor',
      projectRoot: __dirname,
      webpackConfig: config,
      targetArchs: ['arm', 'arm64', 'ia32'],
      tnsJavaClassesOptions: { packages: ['tns-core-modules'] },
      useLibs: false
    }));
  }
  if ( uglify ) {
    // config.plugins.push(new webpack.LoaderOptionsPlugin({ minimize: true }));
    config.plugins.push(new ParallelUglifyPlugin({
      workerCount: os.cpus().length,
      uglifyES: {
        compress: platform !== 'android',
        mangle: {
          reserved: nsWebpack.uglifyMangleExcludes.concat(dropDownMangleExcludes)
        },
        ecma: 6,
        safari10: platform !== 'android',
        warnings: 'verbose',
      }
    }));
  }
  return config;
};
<commit_msg>fix(8): fix webpack config<commit_after>const { resolve, join } = require('path');

const webpack = require('webpack');
const nsWebpack = require('nativescript-dev-webpack');
const nativescriptTarget = require('nativescript-dev-webpack/nativescript-target');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const { NativeScriptWorkerPlugin } = require('nativescript-worker-loader/NativeScriptWorkerPlugin');

const os = require('os');
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
const cacheBusterTimestamp = Date.now().toString(36);

module.exports = env => {
  const platform = env && (env.android && 'android' || env.ios && 'ios');
  if ( !platform ) {
    throw new Error('You need to provide a target platform!');
  }
  const platforms = ['ios', 'android'];
  const ngToolsWebpackOptions = { tsConfigPath: 'tsconfig.aot.json' };
  const { snapshot, uglify, report, aot } = env;

  const config = {
    context: resolve('./app'),
    target: nativescriptTarget,
    entry: {
      bundle: aot ? './main.aot.ts' : './main.ts',
      vendor: './vendor',
    },
    output: {
      pathinfo: true,
      // Default destination inside platforms/<platform>/...
      path: resolve(nsWebpack.getAppPath(platform)),
      libraryTarget: 'commonjs2',
      filename: `[name]_${cacheBusterTimestamp}.js`,
      chunkFilename: '[id].[chunkhash].js',
    },
    resolve: {
      extensions: ['.ts', '.js', '.scss', '.css'],
      // Resolve {N} system modules from tns-core-modules
      modules: [
        'node_modules/tns-core-modules',
        'node_modules',
      ],
      alias: {
        '~': resolve('./app')
      },
      // don't resolve symlinks to symlinked modules
      // symlinks: false
    },
    resolveLoader: {
      // don't resolve symlinks to symlinked loaders
      symlinks: false
    },
    node: {
      // Disable node shims that conflict with NativeScript
      'http': false,
      'timers': false,
      'setImmediate': false,
      'fs': 'empty',
    },
    module: {
      rules: [
        { test: /\.html$|\.xml$/, use: 'raw-loader' },

        // tns-core-modules reads the app.css and its imports using css-loader
        { test: /\/app\.css$/, use: 'css-loader?url=false' },
        { test: /\/app\.scss$/, use: ['css-loader?url=false', 'sass-loader'] },

        // Angular components reference css files and their imports using raw-loader
        { test: /\.css$/, exclude: /\/app\.css$/, use: 'raw-loader' },
        { test: /\.scss$/, exclude: /\/app\.scss$/, use: ['raw-loader', 'resolve-url-loader', 'sass-loader'] },

        // Compile TypeScript files with ahead-of-time compiler.
        {
          test: /.ts$/, use: [
            'nativescript-dev-webpack/moduleid-compat-loader',
            { loader: '@ngtools/webpack', options: ngToolsWebpackOptions },
            { loader: 'angular-router-loader?aot=true' }
          ]
        },
        { test: /\.json$/, use: [{ loader: 'json-loader' }] }
      ],
    },
    plugins: [
      // Vendor libs go to the vendor.js chunk
      new webpack.optimize.CommonsChunkPlugin({
        name: ['vendor'],
        filename: `vendor_${cacheBusterTimestamp}.js`
      }),
      // Define useful constants like TNS_WEBPACK
      new webpack.DefinePlugin({
        'global.TNS_WEBPACK': 'true',
      }),
      // Copy assets to out dir. Add your own globs as needed.
      new CopyWebpackPlugin(
        [
          { from: 'App_Resources/**' },
          { from: 'assets/**' },
          { from: 'fonts/**' },
          { from: '**/*.jpg' },
          { from: '**/*.png' },
          { from: '**/*.xml' }
          ],
        // usually used for local json file
        // if testing out wip backend apis
        { ignore: ['assets/json/**'] }
      ),

      // Generate a bundle starter script and activate it in package.json
      new nsWebpack.GenerateBundleStarterPlugin([
        `./vendor_${cacheBusterTimestamp}`,
        `./bundle_${cacheBusterTimestamp}`
      ]),
      // Support for web workers since v3.2
      new NativeScriptWorkerPlugin(),
      // AngularCompilerPlugin with augmented NativeScript filesystem to handle platform specific resource resolution.
      new nsWebpack.NativeScriptAngularCompilerPlugin(
        Object.assign({
          entryModule: resolve(__dirname, 'app/app.module#AppModule'),
          skipCodeGeneration: !aot,
          platformOptions: {
            platform,
            platforms,
            // ignore: ['App_Resources']
          },
        }, ngToolsWebpackOptions)
      ),
      // Does IPC communication with the {N} CLI to notify events when running in watch mode.
      new nsWebpack.WatchStateLoggerPlugin(),
    ],
  };
  if ( report ) {
    // Generate report files for bundles content
    config.plugins.push(new BundleAnalyzerPlugin({
      analyzerMode: 'static',
      openAnalyzer: false,
      generateStatsFile: true,
      reportFilename: join(__dirname, 'report', `report.html`),
      statsFilename: join(__dirname, 'report', `stats.json`),
    }));
  }
  if ( snapshot ) {
    config.plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({
      chunk: 'vendor',
      projectRoot: __dirname,
      webpackConfig: config,
      targetArchs: ['arm', 'arm64', 'ia32'],
      tnsJavaClassesOptions: { packages: ['tns-core-modules'] },
      useLibs: false
    }));
  }
  if ( uglify ) {
    // config.plugins.push(new webpack.LoaderOptionsPlugin({ minimize: true }));
    config.plugins.push(new ParallelUglifyPlugin({
      workerCount: os.cpus().length,
      uglifyES: {
        compress: platform !== 'android',
        ecma: 6,
        safari10: platform !== 'android',
        warnings: 'verbose',
      }
    }));
  }
  return config;
};
<|endoftext|>


<commit_before>// objective:
// insert a dash between two CONSECUTIVE odd numbers

// solution:
function DashInsert(str) {
  let idk = 0;
  // loop through to find odd numbers
  while (idk < str.length - 1) {
    // check if current number is odd and the next number is also odd
    // needs remainder operator - to return the remainder of a division operation
    if (Number(str[idk]) % 2 === 1 && Number(str[idk + 1]) % 2 === 1) {
      // if it is, then add dash between the two odd numbers

      str = str.slice(0, idk + 1) + "-" + str.slice(idk + 1);
      idx = idk + 2;
    } else {
      idk++;
    }
  }

  return str;
}

console.log(DashInsert("23522"));
<commit_msg>fix typo<commit_after>// objective:
// insert a dash between two CONSECUTIVE odd numbers

// solution:
function DashInsert(str) {
  let idk = 0;
  // loop through to find odd numbers
  while (idk < str.length - 1) {
    // check if current number is odd and the next number is also odd
    // needs remainder operator - to return the remainder of a division operation
    if (Number(str[idk]) % 2 === 1 && Number(str[idk + 1]) % 2 === 1) {
      // if it is, then add dash between the two odd numbers

      str = str.slice(0, idk + 1) + "-" + str.slice(idk + 1);
      idk = idk + 2;
    } else {
      idk++;
    }
  }

  return str;
}

console.log(DashInsert("23522"));
<|endoftext|>


<commit_before>require('firebase')
require('hex-to-rgba')
require('lodash')
require('material-ui')
require('material-ui-next')
require('moment')
require('object-assign')
require('prop-types')
require('promise')
require('react')
require('react-color')
require('react-custom-scrollbars')
require('react-dom')
require('react-firebaseui')
require('react-ga')
require('react-hot-loader')
require('react-intl')
require('react-measure')
require('react-relay')
require('react-router')
require('react-tap-event-plugin')
require('react-transition-group')
require('whatwg-fetch')
require('xregexp')
<commit_msg>Commenting<commit_after>// Add the modules that we use in client JS.
// These will be bundled into vendor.js, so that our vendor JS
// filename hash will not change when we modify app code.
require('firebase')
require('hex-to-rgba')
require('lodash')
require('material-ui')
require('material-ui-next')
require('moment')
require('object-assign')
require('prop-types')
require('promise')
require('react')
require('react-color')
require('react-custom-scrollbars')
require('react-dom')
require('react-firebaseui')
require('react-ga')
require('react-hot-loader')
require('react-intl')
require('react-measure')
require('react-relay')
require('react-router')
require('react-tap-event-plugin')
require('react-transition-group')
require('whatwg-fetch')
require('xregexp')
<|endoftext|>


<commit_before>function Ball(numAverages) {
    Particle.call(this, numAverages);

    this.gravityAccel = 3;
    this.maxY = 100;
    this.maxVel = 100;
}

Ball.prototype = Object.create(Particle.prototype);
Ball.prototype.constructor = Ball;

Ball.prototype.tick = function() {
    //Particle.prototype.tick.call(this); // Call super's tick method

    // Update Y-position
    this.y += this.yVel;
    if (this.y+this.yVel < this.maxY) {
        //this.y += this.yVel;
    } else if (this.y < this.maxY) {
        this.y = this.maxY;
    }

    // Update Y-velocity
    this.yVel += this.yAccel;
    if (this.y == this.maxY) {
        // Bounce off of maxY coordinate
        this.yVel = -.1*this.yVel

    } else if (this.y <= 0 && this.yVel < 0) {
        // Bounce off of the ceiling
        this.yVel = -this.yVel;

    } else if (this.yVel > this.maxVel) {
        // Keep yVel below maxVel
        this.yVel = this.maxVel;

    }

    // Update Y-acceleration
    this.yAccel += this.gravityAccel;
    if (this.yAccel > this.gravityAccel) {
        this.yAccel = this.gravityAccel;
    }

    // Stop the ball if it is resting on the maxY coordinate
    if (Math.abs(this.yVel) < .25 && this.y > this.maxY-10) {
        //this.y = this.maxY;
    }
}

var BouncingBalls = function(canvas, analyser) {

    this.canvas = canvas;
    this.analyser = analyser;
    this.drawContext = this.canvas.getContext('2d');

    this.lights = [];
    this.numLights = 750;

    var radius = canvas.width / this.numLights;
    radius /= 2;
    for (var i = 0; i < this.numLights; i++) {
        this.lights.push(new Ball(60));
        this.lights[i].x = radius + 2*radius*i;
        this.lights[i].y = .75*canvas.height;
        this.lights[i].maxY = .75*canvas.height;
    }
}

BouncingBalls.prototype.draw = function() {
    var canvas = this.canvas;
    var drawContext = this.drawContext;
    var freqDomain = new Float32Array(this.analyser.frequencyBinCount);

    drawContext.clearRect(0, 0, canvas.width, canvas.height);
    this.analyser.getFloatFrequencyData(freqDomain);

    var maxRadius = 7.5;
    var minRadius = 7.5;
    var maxHeight = 500;

    var maxFreq = 770;
    var minFreq = 20;
    var samplesPer = (maxFreq-minFreq) / this.lights.length;
    var numBars = (maxFreq - minFreq) / samplesPer;
    var barWidth =  3;

    for (var i = 0; i < this.lights.length; i++) {

        var value = 0;
        for (var x = 0; x < samplesPer; x++) {
            value += freqDomain[i*samplesPer + x];
            value -= this.analyser.minDecibels;
            value -= weight(Visualizer.frequencyPerBin * (i*samplesPer+x));
        }
        value /= samplesPer;
        value = nonNegative(value);
        var percent = value / Visualizer.decibelRange;

        this.lights[i].updateAverageIntensity(percent);

        percent = Math.abs(this.lights[i].averageIntensity - percent);
        this.lights[i].updateAverageIntensityDiff(percent);

        percent = percent+this.lights[i].averageIntensityDiff;
        if (percent > .01 && this.lights[i].y >= .75*canvas.height) {
            this.lights[i].yAccel = -50*percent;
            this.lights[i].hue = 360*this.lights[i].yAccel/5;
        }

        //this.lights[i].hue = 360*this.lights[i].yAccel/5;
        this.lights[i].tick();

        var radius = maxRadius * percent;
        if (radius < minRadius)
            radius = minRadius;

        drawContext.beginPath();
        drawContext.arc(this.lights[i].x, this.lights[i].y, radius, 0, 2*Math.PI, false);
        drawContext.fillStyle = 'hsl(' + this.lights[i].hue + ', 100%, 50%)';
        drawContext.fill();
    }
}<commit_msg>Changed velocities for balls<commit_after>function Ball(numAverages) {
    Particle.call(this, numAverages);

    this.gravityAccel = 6;
    this.maxY = 100;
    this.maxVel = 100;
}

Ball.prototype = Object.create(Particle.prototype);
Ball.prototype.constructor = Ball;

Ball.prototype.tick = function() {
    //Particle.prototype.tick.call(this); // Call super's tick method

    // Update Y-position
    this.y += this.yVel;
    if (this.y+this.yVel < this.maxY) {
        //this.y += this.yVel;
    } else if (this.y < this.maxY) {
        this.y = this.maxY;
    }

    // Update Y-velocity
    this.yVel += this.yAccel;
    if (this.y == this.maxY) {
        // Bounce off of maxY coordinate
        this.yVel = -.1*this.yVel

    } else if (this.y <= 0 && this.yVel < 0) {
        // Bounce off of the ceiling
        this.yVel = -this.yVel;

    } else if (this.yVel > this.maxVel) {
        // Keep yVel below maxVel
        this.yVel = this.maxVel;

    }

    // Update Y-acceleration
    this.yAccel += this.gravityAccel;
    if (this.yAccel > this.gravityAccel) {
        this.yAccel = this.gravityAccel;
    }

    // Stop the ball if it is resting on the maxY coordinate
    if (Math.abs(this.yVel) < .25 && this.y > this.maxY-10) {
        //this.y = this.maxY;
    }
}

var BouncingBalls = function(canvas, analyser) {

    this.canvas = canvas;
    this.analyser = analyser;
    this.drawContext = this.canvas.getContext('2d');

    this.lights = [];
    this.numLights = 750;

    var radius = canvas.width / this.numLights;
    radius /= 2;
    for (var i = 0; i < this.numLights; i++) {
        this.lights.push(new Ball(60));
        this.lights[i].x = radius + 2*radius*i;
        this.lights[i].y = .75*canvas.height;
        this.lights[i].maxY = .75*canvas.height;
    }
}

BouncingBalls.prototype.draw = function() {
    var canvas = this.canvas;
    var drawContext = this.drawContext;
    var freqDomain = new Float32Array(this.analyser.frequencyBinCount);

    drawContext.clearRect(0, 0, canvas.width, canvas.height);
    this.analyser.getFloatFrequencyData(freqDomain);

    var maxRadius = 7.5;
    var minRadius = 7.5;
    var maxHeight = 500;

    var maxFreq = 770;
    var minFreq = 20;
    var samplesPer = (maxFreq-minFreq) / this.lights.length;
    var numBars = (maxFreq - minFreq) / samplesPer;
    var barWidth =  3;

    for (var i = 0; i < this.lights.length; i++) {

        var value = 0;
        for (var x = 0; x < samplesPer; x++) {
            value += freqDomain[i*samplesPer + x];
            value -= this.analyser.minDecibels;
            value -= weight(Visualizer.frequencyPerBin * (i*samplesPer+x));
        }
        value /= samplesPer;
        value = nonNegative(value);
        var percent = value / Visualizer.decibelRange;

        this.lights[i].updateAverageIntensity(percent);

        percent = Math.abs(this.lights[i].averageIntensity - percent);
        this.lights[i].updateAverageIntensityDiff(percent);

        percent = percent+this.lights[i].averageIntensityDiff;
        if (percent > .01 && this.lights[i].y >= .75*canvas.height) {
            this.lights[i].yAccel = -15*percent;
            this.lights[i].hue = 360*this.lights[i].yAccel/5;
        }

        //this.lights[i].hue = 360*this.lights[i].yAccel/5;
        this.lights[i].tick();

        var radius = maxRadius * percent;
        if (radius < minRadius)
            radius = minRadius;

        drawContext.beginPath();
        drawContext.arc(this.lights[i].x, this.lights[i].y, radius, 0, 2*Math.PI, false);
        drawContext.fillStyle = 'hsl(' + this.lights[i].hue + ', 100%, 50%)';
        drawContext.fill();
    }
}
<|endoftext|>


<commit_before>/*
	Name: jquery.swipeButton.js
	Author: Andy Matthews
	Website: http://andyMatthews.net
	Packed With: http://jsutility.pjoneil.net/
*/
(function($){$.fn.swipeDelete=function(o){o=$.extend({},$.fn.swipeDelete.defaults,o);return this.each(function(i,el){var $e=$(el),$parent=$(el).parent('ul');$e.bind(o.direction,function(e){var $li=$(this);$('div.ui-btn',$parent).remove();var $swipeBtn=$(''+o.btnLabel+'').attr({'data-role':'button','data-inline':'true','class':o.btnClass,'data-theme':o.btnTheme,'href':$li.data('swipeurl')}).bind('click tap',o.click);$li.prepend($swipeBtn).find('.'+o.btnClass).button();$('div a:not('+o.btnClass+')',$li).bind('click.swipe',function(e){e.stopPropagation();e.preventDefault();$(this).unbind('click.swipe');$li.removeClass('ui-btn-active').find('div.ui-btn').remove()})})})};$.fn.swipeDelete.defaults={direction:'swiperight',btnLabel:'Delete',btnTheme:'e',btnClass:'aSwipeBtn',click:function(e){e.preventDefault();$(this).parents('li').remove()}}})(jQuery);<commit_msg>Updating swipeButton to be compatible with the pending release of jQuery Mobile 1.1<commit_after>/*
	Name: jquery.swipeButton.js
	Author: Andy Matthews
	Website: http://andyMatthews.net
	Packed With: http://jsutility.pjoneil.net/
*/
(function($){$.fn.swipeDelete=function(o){o=$.extend({},$.fn.swipeDelete.defaults,o);return this.each(function(i,el){var $e=$(el),$parent=$(el).parent('ul');$e.bind(o.direction,function(e){var $li=$(this);$('div.ui-btn, .'+o.btnClass,$parent).remove();var $swipeBtn=$(''+o.btnLabel+'').attr({'data-role':'button','data-inline':'true','class':o.btnClass,'data-theme':o.btnTheme,'href':$li.data('swipeurl')}).bind('click tap',o.click);$li.prepend($swipeBtn).find('.'+o.btnClass).button();$('div a:not('+o.btnClass+')',$li).bind('click.swipe',function(e){e.stopPropagation();e.preventDefault();$(this).unbind('click.swipe');$li.removeClass('ui-btn-active').find('div.ui-btn').remove()})})})};$.fn.swipeDelete.defaults={direction:'swiperight',btnLabel:'Delete',btnTheme:'e',btnClass:'aSwipeBtn',click:function(e){e.preventDefault();$(this).parents('li').remove()}}})(jQuery);<|endoftext|>


<commit_before>/**
 * Creates an instance of the Tags View
 *
 * @constructor
 * @this {Tags}
 * @param {Document} document The document to be shown in the Tags view.
 * @param {DIV} container The conatiner div for the Tags view.
 * @param {DocumentDialog} parent The parent document dialog.
 */
Tags = function(document,container,parent){
	this.type = "tags";
	this.container = container;
	this.stopped = true;
	this.document = document;
	this.container = container;
	this.parent = parent;
	this.lp = new LinkProcessor();
	this.documentScope = EditionProperties.documentScope;
	this.initialize();
}

/**
 * Initializes the tag cloud to display the tags and activates pagination and/or scope selection panels
 *
 * @this {Tags}
 */
Tags.prototype.initialize = function(){
	var context = this;
	this.buttonPanel = $('<div/>').appendTo(this.container);
	this.buttonPanel.addClass('buttonPanel');
	this.contentPanel = $('<div/>').appendTo(this.container);
	$(this.contentPanel).css('overflow','auto');
	this.parent.facetSelector.setTriggerFunc(function(facetSelection){
		context.display();
		context.parent.facetsChanged(facetSelection);
	});
	this.parent.paginator.setTriggerFunc(function(page){
		context.showPage(page);
		context.parent.pageChanged(page);
	});
	if( EditionProperties.scopeSelection ){
		var id = 'scope'+EditionGui.getIndependentId();
		var documentTags = $("<input type='radio' name='"+id+"'>"+Util.getString('documentTags')+"</input>").appendTo(this.buttonPanel);
		var tagsByPages = $("<input type='radio' name='"+id+"'>"+Util.getString('tagsByPages')+"</input>").appendTo(this.buttonPanel);
		if( this.documentScope ){
			$(documentTags).attr('checked',true);
		}
		else {
			$(tagsByPages).attr('checked',true);
		}
		var setScope = function(scope){
			if( context.documentScope != scope ){
				if( scope ){
					context.parent.hidePagination();
				}
				else {
					context.parent.showPagination();
				}
				context.documentScope = scope;
				context.display(context.parent.page);
				context.resize();
			}
		};
		$(documentTags).click(function(){
			setScope(true);
		});
		$(tagsByPages).click(function(){
			setScope(false);
		});
	}
}

/**
 * Retrieves and shows the tags for a given page by updating the tag cloud.
 *
 * @this {Tags}
 * @param {number} page The tags of the given page will be shown (p = 0 for all tags of the document).
 */
Tags.prototype.show = function(page){
	var context = this;
	var facets = this.parent.facetSelector.getFacetString();
	if( facets == '' ){
		$(Util.getAlertMessage(Util.getString('selectFacetsAlert'))).appendTo(this.contentPanel);
		return;
	}
	if( !this.stopped ){
		this.parent.stopProcessing();
	}
	this.stopped = false;
	this.parent.startProcessing();
	var failure = function(errorObject){
		if( !context.stopped ){
			$(Util.getErrorMessage(errorObject.status)).appendTo(context.contentPanel);
			context.parent.stopProcessing();
		}
	}
	var success = function(xml){
		if( !context.stopped ){
			var tagArray = Util.getTags($(xml).find('tag'));
			context.tags = tagArray;
			var trigger = function(){
				context.lp.appendTooltips(context.contentPanel);
				context.parent.stopProcessing();
			};
			$(context.contentPanel).jQCloud(tagArray,{trigger:trigger});
		}
	}
	DocumentServerConnection.getDocumentTags(context.document,page,facets,success,failure);
};

/**
 * Display all tags of the document
 *
 * @this {Tags}
 */
Tags.prototype.showTags = function(){
	$(this.contentPanel).empty();
	this.show(0);
};

/**
 * Display tags mentioned on a given page.
 *
 * @this {Tags}
 * @param {number} page The tags of the given page will be shown.
 */
Tags.prototype.showPage = function(page){
	this.actualPage = page;
	$(this.contentPanel).empty();
	this.show(page);
};

/**
 * Display the tags for the document (page = 0) or a given page (page > 0)
 *
 * @this {Tags}
 * @param {number} page The page to be shown.
 */
Tags.prototype.display = function(page){
	if( this.documentScope ){
		this.showTags();
	}
	else {
		page ? this.parent.paginator.setPage(page,false) : this.parent.paginator.setPage(1,false);
	}
};

/**
 * Resizes the tag cloud.
 *
 * @this {Tags}
 */
Tags.prototype.resize = function(){
	var context = this;
	$(this.contentPanel).css('width','100%');
	$(this.contentPanel).css('height',($(this.container).height()-$(this.buttonPanel).height())+'px');
	if( typeof this.tags != 'undefined' ){
		$(this.contentPanel).empty();
		var trigger = function(){
			context.lp.appendTooltips(context.contentPanel);
		};
		$(this.contentPanel).jQCloud(this.tags,{trigger:trigger});
		this.lp.appendTooltips(this.contentPanel);
	}
};

/**
 * Updates this Tags view if its parent document dialog is linked to other views for the same document and a 'pageChange' or 'facetsChange' event was performed in one of these other linked views
 *
 * @this {Tags}
 * @param {JSON} change The information for the view update. It contains a type (e.g. 'pageChange') and a data information (e.g. the new page number in case of a 'pageChange' event)
 */
Tags.prototype.onChange = function(change){
	if( change.type == "facetsChange" ){
		this.parent.facetSelector.setFacetSelection(change.data);
		this.context.display(this.parent.page);
	}
	if( change.type == "pageChange" ){
		if( this.actualPage != change.data ){
			this.parent.page = change.data;
			this.parent.paginator.setPage(change.data,true);
			this.showPage(change.data);
		}
	}
};
<commit_msg>removed linked windows page bug<commit_after>/**
 * Creates an instance of the Tags View
 *
 * @constructor
 * @this {Tags}
 * @param {Document} document The document to be shown in the Tags view.
 * @param {DIV} container The conatiner div for the Tags view.
 * @param {DocumentDialog} parent The parent document dialog.
 */
Tags = function(document,container,parent){
	this.type = "tags";
	this.container = container;
	this.stopped = true;
	this.document = document;
	this.container = container;
	this.parent = parent;
	this.lp = new LinkProcessor();
	this.documentScope = EditionProperties.documentScope;
	this.initialize();
}

/**
 * Initializes the tag cloud to display the tags and activates pagination and/or scope selection panels
 *
 * @this {Tags}
 */
Tags.prototype.initialize = function(){
	var context = this;
	this.buttonPanel = $('<div/>').appendTo(this.container);
	this.buttonPanel.addClass('buttonPanel');
	this.contentPanel = $('<div/>').appendTo(this.container);
	$(this.contentPanel).css('overflow','auto');
	this.parent.facetSelector.setTriggerFunc(function(facetSelection){
		$(context.contentPanel).empty();
		if( context.documentScope ){
			context.showTags();
		}
		else {
			context.show(context.parent.page);
		}
		context.parent.facetsChanged(facetSelection);
	});
	this.parent.paginator.setTriggerFunc(function(page){
		context.showPage(page);
		context.parent.pageChanged(page);
	});
	if( EditionProperties.scopeSelection ){
		var id = 'scope'+EditionGui.getIndependentId();
		var documentTags = $("<input type='radio' name='"+id+"'>"+Util.getString('documentTags')+"</input>").appendTo(this.buttonPanel);
		var tagsByPages = $("<input type='radio' name='"+id+"'>"+Util.getString('tagsByPages')+"</input>").appendTo(this.buttonPanel);
		if( this.documentScope ){
			$(documentTags).attr('checked',true);
		}
		else {
			$(tagsByPages).attr('checked',true);
		}
		var setScope = function(scope){
			if( context.documentScope != scope ){
				if( scope ){
					context.parent.hidePagination();
				}
				else {
					context.parent.showPagination();
				}
				context.documentScope = scope;
				context.display(context.parent.page);
				context.resize();
			}
		};
		$(documentTags).click(function(){
			setScope(true);
		});
		$(tagsByPages).click(function(){
			setScope(false);
		});
	}
}

/**
 * Retrieves and shows the tags for a given page by updating the tag cloud.
 *
 * @this {Tags}
 * @param {number} page The tags of the given page will be shown (p = 0 for all tags of the document).
 */
Tags.prototype.show = function(page){
	var context = this;
	var facets = this.parent.facetSelector.getFacetString();
	if( facets == '' ){
		$(Util.getAlertMessage(Util.getString('selectFacetsAlert'))).appendTo(this.contentPanel);
		return;
	}
	if( !this.stopped ){
		this.parent.stopProcessing();
	}
	this.stopped = false;
	this.parent.startProcessing();
	var failure = function(errorObject){
		if( !context.stopped ){
			$(Util.getErrorMessage(errorObject.status)).appendTo(context.contentPanel);
			context.parent.stopProcessing();
		}
	}
	var success = function(xml){
		if( !context.stopped ){
			var tagArray = Util.getTags($(xml).find('tag'));
			context.tags = tagArray;
			var trigger = function(){
				context.lp.appendTooltips(context.contentPanel);
				context.parent.stopProcessing();
			};
			$(context.contentPanel).jQCloud(tagArray,{trigger:trigger});
		}
	}
	DocumentServerConnection.getDocumentTags(context.document,page,facets,success,failure);
};

/**
 * Display all tags of the document
 *
 * @this {Tags}
 */
Tags.prototype.showTags = function(){
	$(this.contentPanel).empty();
	this.show(0);
};

/**
 * Display tags mentioned on a given page.
 *
 * @this {Tags}
 * @param {number} page The tags of the given page will be shown.
 */
Tags.prototype.showPage = function(page){
	this.actualPage = page;
	$(this.contentPanel).empty();
	this.show(page);
};

/**
 * Display the tags for the document (page = 0) or a given page (page > 0)
 *
 * @this {Tags}
 * @param {number} page The page to be shown.
 */
Tags.prototype.display = function(page){
	if( this.documentScope ){
		this.showTags();
	}
	else {
		page ? this.parent.paginator.setPage(page,false) : this.parent.paginator.setPage(1,false);
	}
};

/**
 * Resizes the tag cloud.
 *
 * @this {Tags}
 */
Tags.prototype.resize = function(){
	var context = this;
	$(this.contentPanel).css('width','100%');
	$(this.contentPanel).css('height',($(this.container).height()-$(this.buttonPanel).height())+'px');
	if( typeof this.tags != 'undefined' ){
		$(this.contentPanel).empty();
		var trigger = function(){
			context.lp.appendTooltips(context.contentPanel);
		};
		$(this.contentPanel).jQCloud(this.tags,{trigger:trigger});
		this.lp.appendTooltips(this.contentPanel);
	}
};

/**
 * Updates this Tags view if its parent document dialog is linked to other views for the same document and a 'pageChange' or 'facetsChange' event was performed in one of these other linked views
 *
 * @this {Tags}
 * @param {JSON} change The information for the view update. It contains a type (e.g. 'pageChange') and a data information (e.g. the new page number in case of a 'pageChange' event)
 */
Tags.prototype.onChange = function(change){
	if( change.type == "facetsChange" ){
		this.parent.facetSelector.setFacetSelection(change.data);
		this.context.display(this.parent.page);
	}
	if( change.type == "pageChange" ){
		if( this.actualPage != change.data ){
			this.parent.page = change.data;
			this.parent.paginator.setPage(change.data,true);
			this.showPage(change.data);
		}
	}
};
<|endoftext|>