<commit_before>/**
 * This directive will facilitate the lookups values for entities on the server.
 *
 * User: rowan.massey
 * Date: 07/04/2015
 */

(function () {
    "use strict";

    var injectParams = ["$http", "$q"];

    var customLookup = function ($http, $q) {

        var template =
                '
' +
                '<input type="text" ng-model="value" class="ruaghain-lookup" ng-keyup="onInputKeyUp($event)">' +
                '
' +
                        '
' +
                '{{record[lookupTextField]}}' +
                        '
' +
                    '
' +
                '
' +
                '
' +
                    '<button id="btnSave" ng-click="saveLookup()">Save</button>' +
                    '<button id="btnCancel" ng-click="cancel()">Cancel</button>' +
                '
',

            link = function (scope, element, attributes, ngModelController) {
                if (!ngModelController) return;

                var input = element.find("input");

                /**
                 * Formats the data coming up from the model, into the view
                 */
                ngModelController.$formatters.push(function (modelValue) {
                    if (modelValue) {
                        return {
                            id: modelValue[scope.lookupValueField],
                            value: modelValue[scope.lookupTextField]
                        };
                    }
                });

                /**
                 * This returns the defined value back to the model.
                 */
                ngModelController.$parsers.push(function (viewValue) {
                    var id = viewValue[scope.lookupValueField];
                    var value = viewValue[scope.lookupTextField];
                    return {
                        id: id,
                        value: value
                    };
                });

                //ngModelController.$validators.idExists = function(modelValue, viewValue) {
                //    var value = modelValue || viewValue;
                //    return !ngModelController.$isEmpty(value[scope.lookupValueField])
                //};

                //scope.$watch("value", function(newValue, oldValue) {
                //    var newval = newValue;
                //    var oldval = oldValue;
                //});

                /**
                 *
                 */
                ngModelController.$render = function () {
                    scope.id = ngModelController.$viewValue.id;
                    scope.value = ngModelController.$viewValue.value;
                };

                /**
                 * This code gets executed as soon as an item on the dropdown gets clicked.
                 *
                 * @param item The li item that was selected.
                 */
                scope.onItemSelect = function (item) {
                    input.val(item[scope.lookupTextField]);
                    ngModelController.$setViewValue(item);
                    scope.searching = false;
                    scope.clearResults();
                };

                /**
                 * This method will only search when alphanumeric characters (and the down arrow key) are pressed.
                 * If the ESC key is pressed then the results are cleared.
                 *
                 * @param $event The key press event.
                 */
                scope.onInputKeyUp = function ($event) {
                    var charCode = $event.which;
                    if (charCode === 27 || (charCode != 40 && ngModelController.$isEmpty(input.val()))) {
                        scope.clearResults();
                    } else if (((charCode > 64 && charCode < 91) || (charCode > 96 && charCode < 123) || (charCode === 40))) {
                        if (scope.searching && charCode === 40) {
                            //Don't reissue the search request if the down arrow is pressed multiple times.
                            return;
                        }
                        //Only search when alphanumeric characters have been pressed.
                        scope.search();
                    }
                };

                /**
                 * This method deals with selecting the relevant item that is active in the list
                 *
                 * @param $event The event to be checked for.
                 * @param item The item that was selected.
                 */
                scope.onItemKeyUp = function ($event, item) {
                    var charCode = $event.which;
                    if (charCode === 13) {
                        scope.onItemSelect(item);
                    }
                };

                /**
                 * This method will clear the results of the search if focus has been lost.
                 */
                scope.onBlur = function () {
                    //if (scope.searching) {
                    //    scope.clearResults();
                    //    scope.value = '';
                    //}
                };

                scope.onListKeyDown = function (e) {
                    e.preventDefault();

                    if (e.which === 27) {
                        scope.clearResults();
                    }

                    if (e.which == 40) {
                        var next = e.target.parentElement.nextElementSibling;
                        if (next) {
                            next.firstChild.focus();
                        } else {
                            e.target.parentElement.parentElement.firstElementChild.focus();
                        }
                    } else if (e.which == 38) {
                        var previous = e.target.parentElement.previousElementSibling;
                        if (previous) {
                            previous.firstChild.focus();
                        } else {
                            e.target.parentElement.parentElement.lastElementChild.focus();
                        }
                    }
                };

                /**
                 * This method clears the results of any searches, along with the displaying of the save and cancel buttons
                 */
                scope.clearResults = function () {
                    scope.foundRecords = [];
                    scope.addRecord = false;
                    scope.searching = false;
                };

                /**
                 * Ensure that a promise is returned from the controller, that will get resolved here, which is perfectly acceptable for the minute.
                 */
                scope.search = function () {
                    scope.searching = true;
                    scope.findRestData(input).then(function (data) {
                        scope.addRecord = scope.lookupAllowInsert && (typeof data == 'undefined' || data.length === 0);
                        if (data.length == 1) {
                            scope.onItemSelect(data[0])
                        } else {
                            scope.foundRecords = data;
                        }
                    });
                };

                /**
                 * This method will save a resource if one doesn't exist for the typed in value.
                 */
                scope.saveLookup = function () {
                    var newValue = input.val();
                    var SaveUrl = scope.lookupDatasource().baseUrl;
                    var payload = '{"' + scope.lookupTextField + '":"' + newValue + '"}';

                    var deferred = $q.defer();
                    $http.post(SaveUrl, payload).then(function (result) {
                        scope.getResource(result.headers('location')).then(function (data) {
                            ngModelController.$setViewValue(data);
                            scope.clearResults();
                        });
                    }, function (error) {
                        deferred.reject(error);
                        throw new Error("There was an error saving the record: " + error.data.message);
                    });
                };

                /**
                 * This method executes when the cancel button is pressed.
                 */
                scope.cancel = function () {
                    scope.clearResults();
                    ngModelController.$rollbackViewValue()
                };

                /**
                 * This method will retrieve a given resource for the provided Url
                 *
                 * @param url The url for the required resource.
                 * @returns {*} A promise for the required information.
                 */
                scope.getResource = function (url) {
                    var deferred = $q.defer();
                    $http.get(url).then(function (data) {
                        deferred.resolve(data.data);
                    }, function (error) {
                        deferred.reject(error);
                        throw new Error("There was an error looking up information");
                    });
                    return deferred.promise;
                };
            };

        var controller = ["$scope", function (scope) {
            scope.searching = false;
            scope.lookupAllowInsert = angular.isDefined(scope.lookupAllowInsert) ? scope.lookupAllowInsert : false;

            /**
             * This method finds the entered in information for the rest datasource.
             *
             * @param input The actual input component.
             * @returns {*}
             */
            scope.findRestData = function (input) {
                var deferred = $q.defer();
                var datasource = this.lookupDatasource();
                var actualEnteredValue = input.val();
                var encodedValue = encodeURIComponent("%" + actualEnteredValue + "%");
                $http.get(datasource.baseUrl + datasource.searchUrl + encodedValue).then(function (data) {
                    if (datasource.payload(data.data)) {
                        deferred.resolve(datasource.payload(data.data));
                    } else {
                        //Need to resolve to a blank object, so it returns nothing.
                        deferred.resolve();
                    }
                }, function (error) {
                    deferred.reject(error);
                    throw new Error("There was an error looking up information");
                });
                return deferred.promise;
            };
        }];

        return {
            restrict: "E",
            scope: {
                lookupDatasource: "&",
                lookupTextField: "@",
                lookupValueField: "@",
                lookupAllowInsert: "=?"
            },
            require: "ngModel",
            template: template,
            link: link,
            controller: controller
        };
    };
    customLookup.$inject = injectParams;
    angular.module("ruaghain.lookup-directive", []).directive("customLookup", customLookup);
})();<commit_msg>Managed to finally get the value clearing when the delete or backspace button is clicked. Added in a validator to check if the directive is required, and if so  return it if nothing is selected.<commit_after>/**
 * This directive will facilitate the lookups values for entities on the server.
 *
 * User: rowan.massey
 * Date: 07/04/2015
 */

(function () {
    "use strict";

    var injectParams = ["$http", "$q"];

    var customLookup = function ($http, $q) {

        var template =
                '
' +
                '<input type="text" ng-model="value" class="ruaghain-lookup" ng-keyup="onInputKeyUp($event)">' +
                '
' +
                        '
' +
                '{{record[lookupTextField]}}' +
                        '
' +
                    '
' +
                '
' +
                '
' +
                    '<button id="btnSave" ng-click="saveLookup()">Save</button>' +
                    '<button id="btnCancel" ng-click="cancel()">Cancel</button>' +
                '
',

            link = function (scope, element, attributes, ngModelController) {
                if (!ngModelController) return;

                var input = element.find("input");
                var required = attributes.$attr["required"] != undefined;

                /**
                 * Formats the data coming up from the model, into the view
                 */
                ngModelController.$formatters.push(function (modelValue) {
                    if (modelValue) {
                        return {
                            id: modelValue[scope.lookupValueField],
                            value: modelValue[scope.lookupTextField]
                        };
                    }
                });

                /**
                 * This returns the defined value back to the model.
                 */
                ngModelController.$parsers.push(function (viewValue) {
                    if (viewValue) {
                        var id = viewValue[scope.lookupValueField];
                        var value = viewValue[scope.lookupTextField];
                        return {
                            id: id,
                            value: value
                        };
                    } else {
                        return {
                            id: '',
                            value: ''
                        }
                    }
                });

                /**
                 * This ensures that a value is selected if the required attribute is set.
                 *
                 * @param modelValue
                 * @param viewValue
                 * @returns {boolean}
                 */
                ngModelController.$validators.requiredItemSelected = function (modelValue, viewValue) {
                    var value = modelValue || viewValue;
                    return required ? !ngModelController.$isEmpty(value[scope.lookupValueField]) : true;
                };

                ngModelController.$render = function () {
                    scope.id = ngModelController.$viewValue.id;
                    scope.value = ngModelController.$viewValue.value;
                };

                /**
                 * This code gets executed as soon as an item on the dropdown gets clicked.
                 *
                 * @param item The li item that was selected.
                 */
                scope.onItemSelect = function (item) {
                    input.val(item[scope.lookupTextField]);
                    ngModelController.$setViewValue(item);
                    scope.searching = false;
                    scope.clearResults();
                };

                /**
                 * This method will only search when alphanumeric characters (and the down arrow key) are pressed.
                 * If the ESC key is pressed then the results are cleared.
                 *
                 * @param $event The key press event.
                 */
                scope.onInputKeyUp = function ($event) {
                    var charCode = $event.which;
                    if (charCode === 27 || (charCode != 40 && ngModelController.$isEmpty(input.val()))) {
                        scope.clearResults();
                        //Need to clear the view value completely, otherwise the old value returns
                        ngModelController.$setViewValue(null);
                    } else if (((charCode > 64 && charCode < 91) || (charCode > 96 && charCode < 123) || (charCode === 40))) {
                        if (scope.searching && charCode === 40) {
                            //Don't reissue the search request if the down arrow is pressed multiple times.
                            return;
                        }
                        //Only search when alphanumeric characters have been pressed.
                        scope.search();
                    }
                };

                /**
                 * This method deals with selecting the relevant item that is active in the list
                 *
                 * @param $event The event to be checked for.
                 * @param item The item that was selected.
                 */
                scope.onItemKeyUp = function ($event, item) {
                    var charCode = $event.which;
                    if (charCode === 13) {
                        scope.onItemSelect(item);
                    }
                };

                scope.onListKeyDown = function (e) {
                    e.preventDefault();

                    if (e.which === 27) {
                        scope.clearResults();
                    }

                    if (e.which == 40) {
                        var next = e.target.parentElement.nextElementSibling;
                        if (next) {
                            next.firstChild.focus();
                        } else {
                            e.target.parentElement.parentElement.firstElementChild.focus();
                        }
                    } else if (e.which == 38) {
                        var previous = e.target.parentElement.previousElementSibling;
                        if (previous) {
                            previous.firstChild.focus();
                        } else {
                            e.target.parentElement.parentElement.lastElementChild.focus();
                        }
                    }
                };

                /**
                 * This method clears the results of any searches, along with the displaying of the save and cancel buttons
                 */
                scope.clearResults = function () {
                    scope.foundRecords = [];
                    scope.addRecord = false;
                    scope.searching = false;
                };

                /**
                 * Ensure that a promise is returned from the controller, that will get resolved here, which is perfectly acceptable for the minute.
                 */
                scope.search = function () {
                    scope.searching = true;
                    scope.findRestData(input).then(function (data) {
                        scope.addRecord = scope.lookupAllowInsert && (typeof data == 'undefined' || data.length === 0);
                        if (data.length == 1) {
                            scope.onItemSelect(data[0])
                        } else {
                            scope.foundRecords = data;
                        }
                    });
                };

                /**
                 * This method will save a resource if one doesn't exist for the typed in value.
                 */
                scope.saveLookup = function () {
                    var newValue = input.val();
                    var SaveUrl = scope.lookupDatasource().baseUrl;
                    var payload = '{"' + scope.lookupTextField + '":"' + newValue + '"}';

                    var deferred = $q.defer();
                    $http.post(SaveUrl, payload).then(function (result) {
                        scope.getResource(result.headers('location')).then(function (data) {
                            ngModelController.$setViewValue(data);
                            scope.clearResults();
                        });
                    }, function (error) {
                        deferred.reject(error);
                        throw new Error("There was an error saving the record: " + error.data.message);
                    });
                };

                /**
                 * This method executes when the cancel button is pressed.
                 */
                scope.cancel = function () {
                    scope.clearResults();
                    ngModelController.$rollbackViewValue()
                };

                /**
                 * This method will retrieve a given resource for the provided Url
                 *
                 * @param url The url for the required resource.
                 * @returns {*} A promise for the required information.
                 */
                scope.getResource = function (url) {
                    var deferred = $q.defer();
                    $http.get(url).then(function (data) {
                        deferred.resolve(data.data);
                    }, function (error) {
                        deferred.reject(error);
                        throw new Error("There was an error looking up information");
                    });
                    return deferred.promise;
                };
            };

        var controller = ["$scope", function (scope) {
            scope.searching = false;
            scope.lookupAllowInsert = angular.isDefined(scope.lookupAllowInsert) ? scope.lookupAllowInsert : false;

            /**
             * This method finds the entered in information for the rest datasource.
             *
             * @param input The actual input component.
             * @returns {*}
             */
            scope.findRestData = function (input) {
                var deferred = $q.defer();
                var datasource = this.lookupDatasource();
                var actualEnteredValue = input.val();
                var encodedValue = encodeURIComponent("%" + actualEnteredValue + "%");
                $http.get(datasource.baseUrl + datasource.searchUrl + encodedValue).then(function (data) {
                    if (datasource.payload(data.data)) {
                        deferred.resolve(datasource.payload(data.data));
                    } else {
                        //Need to resolve to a blank object, so it returns nothing.
                        deferred.resolve();
                    }
                }, function (error) {
                    deferred.reject(error);
                    throw new Error("There was an error looking up information");
                });
                return deferred.promise;
            };
        }];

        return {
            restrict: "E",
            scope: {
                lookupDatasource: "&",
                lookupTextField: "@",
                lookupValueField: "@",
                lookupAllowInsert: "=?"
            },
            require: "ngModel",
            template: template,
            link: link,
            controller: controller
        };
    };
    customLookup.$inject = injectParams;
    angular.module("ruaghain.lookup-directive", []).directive("customLookup", customLookup);
})();<|endoftext|>


<commit_before>/**
 * Loady module - Load external JavaScript file(s) and append it to the head of the current document
 * Note: This is NOT a replacement for module loaders available on the market
 *
 * Modified: 2015/09/16
 * @author softwarespot
 */
var loady = (function (document) { // jshint ignore:line
    // Constants

    var _dataAttributes = {
        SOURCE_FILE: 'data-loady-sourcefile'
    };

    // Store the first head node
    var _head = document.head || document.getElementsByTagName('head')[0];

    // Regular expression to strip the JS extension
    var _reJsExtension = /\.js$/;

    // Store previously loaded source file(s)
    var _storageFiles = [];

    // Store the state of the source file(s) i.e. true or false
    var _storageState = [];

    // Return strings of toString() found on the Object prototype
    // Based on the implementation by lodash inc. is* function as well
    const _objectStrings = {
        FUNCTION: '[object Function]',
        STRING: '[object String]'
    };

    // Store the toString method
    var _objectToString = Object.prototype.toString;

    /**
     * Check if a variable is an array datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is an array datatype; otherwise, false
     */
    var isArray = Array.isArray;

    /**
     * Check if a variable is a function datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is a function datatype; otherwise, false
     */
    function isFunction(value) {
        return isObject(value) && _objectToString.call(value) === _objectStrings.FUNCTION;
    }

    /**
     * Check if a variable is an object
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is an object; otherwise, false
     */
    function isObject(value) {
        // Store the typeof value
        var type = typeof value;

        // !!value is basically checking if value is not 'truthy' e.g. null or zero and then inverts that boolean value
        // So, !'Some test' is false and then inverting false is true. There if value contains 'something', continue
        return !!value && (type === 'object' || type === 'function');
    }

    /**
     * Check if a variable is a string datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is a string datatype; otherwise, false
     */
    function isString(value) {
        return typeof value === 'string' || _objectToString.call(value) === _objectStrings.STRING;
    }

    // START: Loader class

    /**
     * ILoader class
     */
    function ILoader() {
        this.destroy();
    }

    /**
     * Loader prototype chain
     *
     * @type {object}
     */
    ILoader.prototype = {
        /**
         * Tidy up open resources, good housekeeping
         *
         * @return {undefined}
         */
        destroy: function () {
            // Final callback function
            this._callback = null;

            // Currently loaded total count.
            // Note: The loaded count is set to -1, due to this.onCompleted incrementing by 1 and checking against this._length,
            // which right now is set to 0
            this._loaded = -1;

            // An array of successfully loaded source file(s)
            this._called = null;

            // An array of source file(s) initially passed in
            this._files = null;

            // Length of the source file(s) initially passed in
            this._length = 0;
        },

        /**
         * Load an array of source file(s)
         *
         * @param {array} sourceFiles An array of source file(s). Note: .js is optional
         * @param {function} callback Callback function to invoke on successful completion.
         * The arguments passed to the callback is an array of loaded scripts and a success parameter of true or false
         * @return {undefined}
         */
        load: function (sourceFiles, callback) {
            // Destroy the previous contents
            this.destroy();

            // This is the only error thrown, due to a callback being required
            if (!isFunction(callback)) {
                throw new Error('Loady: The callback function argument is not a valid function type.');
            }

            // Coerce as an array if the source file is a string
            if (isString(sourceFiles)) {
                sourceFiles = [sourceFiles];
            }

            // Set the callback function property
            this._callback = callback;

            // Check if the source file(s) argument is not an array
            if (!isArray(sourceFiles)) {
                this.onCompleted(false);
                return;
            }

            // Check if any values exist in the array
            if (sourceFiles.length === 0) {
                this.onCompleted(false);
                return;
            }

            // Set to 0, as now all the important checks have passed, thankfully
            this._loaded = 0;
            this._called = [];
            this._files = sourceFiles;
            this._length = sourceFiles.length;

            for (var i = 0; i < this._length; i++) {
                var sourceFile = sourceFiles[i];
                // Strip and append .js to the source file
                sourceFile = sourceFile.replace(_reJsExtension, '') + '.js';

                var index = _storageFiles.indexOf(sourceFile);
                if (index !== -1) {
                    this.onCompleted(_storageState[index] !== true);
                    return;
                }

                // Load the script file and append to the current document
                this.loadScript(sourceFile);
            }
        },

        /**
         * Load a script and append to the first HEAD node in the DOM
         *
         * @param {string} sourceFile Script source location that can be absolute or relative
         * @return {undefined}
         */
        loadScript: function (sourceFile) {
            var node = document.createElement('script');
            node.src = sourceFile;
            // node.text = file;

            // node.type = 'text/javascript';
            // node.charset = 'utf-8';

            node.async = true;

            node.setAttribute(_dataAttributes.SOURCE_FILE, sourceFile);

            // Attach events. Note: Bind is used to 'bind' to the context of 'this' i.e. the class
            node.addEventListener('load', this.onLoad.bind(this), false);
            node.addEventListener('error', this.onLoad.bind(this), false);

            // Append to the HEAD node
            _head.appendChild(node);

            // Push to the internal storage
            _storageFiles.push(sourceFile);
        },

        /**
         * Increment the loaded scripts property and invoke the callback function on completion
         *
         * @param {boolean} isSuccess Whether the request was successful
         * @return {undefined}
         */
        onCompleted: function (isSuccess) {
            if (isSuccess !== true) {
                isSuccess = false;
            }

            // Increment the loaded total count
            this._loaded++;

            if (this._length === this._loaded) {
                this._callback.apply(this, [this._called, isSuccess]);
                this.destroy();
            }
        },

        /**
         * The 'load' or 'error' callback function for the event listeners
         *
         * @param {event} event Event object passed by the event listener
         * @return {undefined}
         */
        onLoad: function (event) {
            // Store the type of event and whether it was a 'load' or 'error' type event
            var type = event.type;
            var isLoaded = type === 'load';

            if (isLoaded || type === 'error') {
                var node = event.currentTarget || event.srcElement;
                if (!node) {
                    return;
                }

                // Remove assigned events
                node.removeEventListener('load', this.onLoad, false);
                node.removeEventListener('error', this.onLoad, false);

                // Display details about the inserted SCRIPT node and script
                if (isLoaded) {
                    // console.log('Loader.onLoad: Loaded/Error callback invoked, Time: %i', +(new Date()));
                    // console.log('Loader.onLoad: Attribute = ' + node.getAttribute(_dataAttributes.SOURCE_FILE));

                    // Get the source file directly from the data-* attribute
                    var sourceFile = node.getAttribute(_dataAttributes.SOURCE_FILE);

                    // Push the state of the source file
                    _storageState.push(true);

                    // Push to the successfully loaded scripts
                    this._called.push(sourceFile);
                }

                this.onCompleted(true);
            }
        }
    };

    // END: Loader class

    // Public API

    return function (sourceFiles, callback) {
        // Create an instance of the internal loader class
        var loady = new ILoader();

        // Load the source file(s)
        loady.load(sourceFiles, callback);
    };
})(this.document);
<commit_msg>Fixed comment<commit_after>/**
 * Loady module - Load external JavaScript file(s) and append it to the head of the current document
 * Note: This is NOT a replacement for module loaders available on the market
 *
 * Modified: 2015/09/16
 * @author softwarespot
 */
var loady = (function (document) { // jshint ignore:line
    // Constants

    var _dataAttributes = {
        SOURCE_FILE: 'data-loady-sourcefile'
    };

    // Store the first head node
    var _head = document.head || document.getElementsByTagName('head')[0];

    // Regular expression to strip the JS extension
    var _reJsExtension = /\.js$/;

    // Store previously loaded source file(s)
    var _storageFiles = [];

    // Store the state of the source file(s) i.e. true or false
    var _storageState = [];

    // Return strings of toString() found on the Object prototype
    // Based on the implementation by lodash inc. is* function as well
    const _objectStrings = {
        FUNCTION: '[object Function]',
        STRING: '[object String]'
    };

    // Store the toString method
    var _objectToString = Object.prototype.toString;

    /**
     * Check if a variable is an array datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is an array datatype; otherwise, false
     */
    var isArray = Array.isArray;

    /**
     * Check if a variable is a function datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is a function datatype; otherwise, false
     */
    function isFunction(value) {
        return isObject(value) && _objectToString.call(value) === _objectStrings.FUNCTION;
    }

    /**
     * Check if a variable is an object
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is an object; otherwise, false
     */
    function isObject(value) {
        // Store the typeof value
        var type = typeof value;

        // !!value is basically checking if value is not 'truthy' e.g. null or zero and then inverts that boolean value
        // So, !'Some test' is false and then inverting false is true. There if value contains 'something', continue
        return !!value && (type === 'object' || type === 'function');
    }

    /**
     * Check if a variable is a string datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is a string datatype; otherwise, false
     */
    function isString(value) {
        return typeof value === 'string' || _objectToString.call(value) === _objectStrings.STRING;
    }

    // START: Loader class

    /**
     * ILoader class
     */
    function ILoader() {
        this.destroy();
    }

    /**
     * Loader prototype chain
     *
     * @type {object}
     */
    ILoader.prototype = {
        /**
         * Tidy up open resources, good housekeeping
         *
         * @return {undefined}
         */
        destroy: function () {
            // Final callback function
            this._callback = null;

            // Currently loaded total count.
            // Note: The loaded count is set to -1, due to this.onCompleted incrementing by 1 and checking against this._length,
            // which right now is set to 0
            this._loaded = -1;

            // An array of successfully loaded source file(s)
            this._called = null;

            // An array of source file(s) initially passed in
            this._files = null;

            // Length of the source file(s) initially passed in
            this._length = 0;
        },

        /**
         * Load an array of source file(s)
         *
         * @param {array} sourceFiles An array of source file(s). Note: .js is optional
         * @param {function} callback Callback function to invoke on successful completion.
         * The arguments passed to the callback is an array of loaded scripts and a success parameter of true or false
         * @return {undefined}
         */
        load: function (sourceFiles, callback) {
            // Destroy the previous contents
            this.destroy();

            // This is the only error thrown, due to a callback being required
            if (!isFunction(callback)) {
                throw new Error('Loady: The callback function argument is not a valid function type.');
            }

            // Coerce as an array if the source file is a string
            if (isString(sourceFiles)) {
                sourceFiles = [sourceFiles];
            }

            // Set the callback function property
            this._callback = callback;

            // Check if the source file(s) argument is not an array
            if (!isArray(sourceFiles)) {
                this.onCompleted(false);
                return;
            }

            // Check if any values exist in the array
            if (sourceFiles.length === 0) {
                this.onCompleted(false);
                return;
            }

            // Set to 0, as now all the important checks have passed, thankfully
            this._loaded = 0;
            this._called = [];
            this._files = sourceFiles;
            this._length = sourceFiles.length;

            for (var i = 0; i < this._length; i++) {
                var sourceFile = sourceFiles[i];
                // Strip and append .js to the source file
                sourceFile = sourceFile.replace(_reJsExtension, '') + '.js';

                var index = _storageFiles.indexOf(sourceFile);
                if (index !== -1) {
                    this.onCompleted(_storageState[index] !== true);
                    return;
                }

                // Load the script file and append to the current document
                this.loadScript(sourceFile);
            }
        },

        /**
         * Load a script and append to the first HEAD node in the DOM
         *
         * @param {string} sourceFile Script source location that can be absolute or relative
         * @return {undefined}
         */
        loadScript: function (sourceFile) {
            var node = document.createElement('script');
            node.src = sourceFile;
            // node.text = file;

            // node.type = 'text/javascript';
            // node.charset = 'utf-8';

            node.async = true;

            node.setAttribute(_dataAttributes.SOURCE_FILE, sourceFile);

            // Attach events
            // Note: Bind is used to 'bind' to the context of 'this' i.e. the current object
            node.addEventListener('load', this.onLoad.bind(this), false);
            node.addEventListener('error', this.onLoad.bind(this), false);

            // Append to the HEAD node
            _head.appendChild(node);

            // Push to the internal storage
            _storageFiles.push(sourceFile);
        },

        /**
         * Increment the loaded scripts property and invoke the callback function on completion
         *
         * @param {boolean} isSuccess Whether the request was successful
         * @return {undefined}
         */
        onCompleted: function (isSuccess) {
            if (isSuccess !== true) {
                isSuccess = false;
            }

            // Increment the loaded total count
            this._loaded++;

            if (this._length === this._loaded) {
                this._callback.apply(this, [this._called, isSuccess]);
                this.destroy();
            }
        },

        /**
         * The 'load' or 'error' callback function for the event listeners
         *
         * @param {event} event Event object passed by the event listener
         * @return {undefined}
         */
        onLoad: function (event) {
            // Store the type of event and whether it was a 'load' or 'error' type event
            var type = event.type;
            var isLoaded = type === 'load';

            if (isLoaded || type === 'error') {
                var node = event.currentTarget || event.srcElement;
                if (!node) {
                    return;
                }

                // Remove assigned events
                node.removeEventListener('load', this.onLoad, false);
                node.removeEventListener('error', this.onLoad, false);

                // Display details about the inserted SCRIPT node and script
                if (isLoaded) {
                    // console.log('Loader.onLoad: Loaded/Error callback invoked, Time: %i', +(new Date()));
                    // console.log('Loader.onLoad: Attribute = ' + node.getAttribute(_dataAttributes.SOURCE_FILE));

                    // Get the source file directly from the data-* attribute
                    var sourceFile = node.getAttribute(_dataAttributes.SOURCE_FILE);

                    // Push the state of the source file
                    _storageState.push(true);

                    // Push to the successfully loaded scripts
                    this._called.push(sourceFile);
                }

                this.onCompleted(true);
            }
        }
    };

    // END: Loader class

    // Public API

    return function (sourceFiles, callback) {
        // Create an instance of the internal loader class
        var loady = new ILoader();

        // Load the source file(s)
        loady.load(sourceFiles, callback);
    };
})(this.document);
<|endoftext|>


<commit_before>const ESCAPE_CHARS = /([\\`*_\[\]<>])/g;

function chomp(string) {
  // string chomp!
  return string.replace(/^\s+/, '').replace(/\s+$/, '');
}

function removeNewlines(string) {
  // remove any new-line chars
  return string.replace("\n", '');
}

function escapeLinkText(string) {
  return string.replace(ESCAPE_CHARS, "\\$1");
}

function determineTitle(title, options={ escape: false }) {
  title = removeNewlines(chomp(title));

  if (options.escape) {
    title = escapeLinkText(title);
  }

  if (title === '') {
    title = "(No Title)";
  }

  return title;
}

exports.formatLink = function(url, title, options={ escape: false }) {
  return "[" + determineTitle(title, options) + "](" + url + ")";
};

exports.formatImage = function(url, title) {
  return "![" + determineTitle(title) + "](" + url + ")";
};

exports.formatList = function(texts) {
  // new line chars are appended at the end of each line
  // to make sure that we'll have a new line char at the very end.
  return texts.map(function(text) {
    return "- " + text + "\n";
  }).join("");
};
<commit_msg>fix the bug that texts are not escaped by default<commit_after>const ESCAPE_CHARS = /([\\`*_\[\]<>])/g;

function chomp(string) {
  // string chomp!
  return string.replace(/^\s+/, '').replace(/\s+$/, '');
}

function removeNewlines(string) {
  // remove any new-line chars
  return string.replace("\n", '');
}

function escapeLinkText(string) {
  return string.replace(ESCAPE_CHARS, "\\$1");
}

function determineTitle(title, options={ escape: true }) {
  title = removeNewlines(chomp(title));

  if (options.escape) {
    title = escapeLinkText(title);
  }

  if (title === '') {
    title = "(No Title)";
  }

  return title;
}

exports.formatLink = function(url, title, options={ escape: true }) {
  return "[" + determineTitle(title, options) + "](" + url + ")";
};

exports.formatImage = function(url, title) {
  return "![" + determineTitle(title) + "](" + url + ")";
};

exports.formatList = function(texts) {
  // new line chars are appended at the end of each line
  // to make sure that we'll have a new line char at the very end.
  return texts.map(function(text) {
    return "- " + text + "\n";
  }).join("");
};
<|endoftext|>


<commit_before>const logAF = function logAF(...args) {
  const error = new Error();
  if (logAF.label && error.stack) {
    const start = error.stack.lastIndexOf`/` + 1;
    const end = error.stack.indexOf(')', start);
    const lineNum = `@${error.stack.slice(start, end)}:`;
    args.unshift(typeof args[0] === 'object' ? `${lineNum}\n` : lineNum);
  }
  Promise.all(args).then(toLog => console.log(...toLog));
};

logAF.label = true;

logAF.options = function logAFOptions(options) {
  if (options.label === false) logAF.label = false;
};

module.exports = logAF;
<commit_msg>(feat) add labelFormat option to logAF--including 'fileName' and 'filePath'<commit_after>const logAF = function logAF(...args) {
  const error = new Error();
  if (logAF.label && error.stack) {
    let lineNum;
    const setFormat = {
      fileName() {
        const start = error.stack.lastIndexOf`/` + 1;
        const end = error.stack.indexOf(')', start);
        lineNum = `@${error.stack.slice(start, end)}:`;
      },
      filePath() {
        const target = error.stack.lastIndexOf`/`;
        const cutoff = error.stack.slice(0, error.stack.indexOf(')', target));
        const newLineForPaths = typeof args[0] !== 'object' ? '\n' : '';
        lineNum = `@${cutoff.slice(cutoff.lastIndexOf`(` + 1)}:${newLineForPaths}`;
      },
    };
    setFormat[logAF.labelFormat]();
    args.unshift(typeof args[0] === 'object' ? `${lineNum}\n` : lineNum);
  }
  Promise.all(args).then(toLog => console.log(...toLog));
};

logAF.label = true;
logAF.labelFormat = 'fileName';

logAF.options = function logAFOptions(options) {
  if (options.label === false) logAF.label = false;
  if (options.labelFormat) {
    const validFormats = ['fileName', 'filePath', 'parent'];
    const desiredFormat = options.labelFormat;
    if (!validFormats.includes(desiredFormat)) {
      const msg = 'AsyncAF Warning: logAF labelFormat option must be set to \'fileName\' (default), \'filePath\', or \'parent\'';
      // eslint-disable-next-line
      console ? console.warn ? console.warn(msg) : console.log ? console.log(msg) : null : null;
    } else logAF.labelFormat = desiredFormat;
  }
};

module.exports = logAF;
<|endoftext|>


<commit_before>'use strict';
/*global module, define, console*/
/*
 * logci - https://github.com/zensh/logci
 *
 * Copyright (c) 2013 Yan Qing
 * Licensed under the MIT license.
 */

(function () {
  var hasOwn = Object.prototype.hasOwnProperty,
    logOptions = {
      url: '',
      token: '',
      slient: {},
      report: {}
    };

  function noop() {}

  function isObject(obj) {
    return typeof obj === 'object';
  }

  function isFunction(fn) {
    return typeof fn === 'function';
  }

  function isDefined(obj) {
    return typeof obj !== 'undefined';
  }

  function each(obj, iterator, context) {
    for (var key in obj) {
      if (hasOwn.call(obj, key)) {
        iterator.call(context, obj[key], key, obj);
      }
    }
  }

  function report(type, messages) {
    if (logOptions.url && logOptions.token) {
      logci.log(type, messages);  //TODO
    }
  }

  function logci(fn) {
    if (isFunction(fn)) {
      try {
        fn();
      } catch (error) {
        report('error', error);
      }
    }
  }

  var _console = console || {},
    _slient = logOptions.slient,
    _report = logOptions.report;

  logci.config = function (options) {
    if (isObject(options)) {
      logOptions.url = options.url || logOptions.url;
      logOptions.token = options.token || logOptions.token;
      if (isObject(options.slient)) {
        each(_slient, function (value, key) {
          value = options.slient[key];
          if (isDefined(value)) {
            _slient[key] = value;
          }
        });
      }
      if (isObject(options.report)) {
        each(_report, function (value, key) {
          value = options.report[key];
          if (isDefined(value)) {
            _report[key] = value;
          }
        });
      }
    }
  };

  each(['log', 'info', 'warn', 'error'], function (method) {
    _console[method] = isFunction(_console[method]) ? _console[method] : noop;
    _slient[method] = false;
    _report[method] = false;
    logci[method] = function () {
      var args = [].slice.call(arguments);
      if (!_slient[method]) {
        _console[method].apply(_console, args);
      }
      if (_report[method]) {
        report(method, args);
      }
    };
  });
  _report.error = true;

  if (typeof module === 'object' && module.exports) {
    module.exports = logci();
  } else if (typeof define === 'function' && define.amd) {
    define(function () {
      return logci;
    });
  }
  if (typeof window === 'object') {
    window.logci = logci;
  }
})();
<commit_msg>fix and improve<commit_after>'use strict';
/*global module, define, console*/
/*
 * logci - https://github.com/zensh/logci
 *
 * Copyright (c) 2013 Yan Qing
 * Licensed under the MIT license.
 */

(function () {
  var hasOwn = Object.prototype.hasOwnProperty,
    _console = console || {},
    _slient = {},
    _report = {},
    logOptions = {
      space: '',
      token: '',
      slient: _slient,
      report: _report
    };

  function noop() {}

  function isObject(obj) {
    return typeof obj === 'object';
  }

  function isFunction(fn) {
    return typeof fn === 'function';
  }

  function isString(str) {
    return typeof str === 'string';
  }

  function isDefined(obj) {
    return typeof obj !== 'undefined';
  }

  function each(obj, iterator, context) {
    for (var key in obj) {
      if (hasOwn.call(obj, key)) {
        iterator.call(context, obj[key], key, obj);
      }
    }
  }

  function setOptions(options) {
    logOptions.space = options.space || logOptions.space;
    logOptions.token = options.token || logOptions.token;
    if (isObject(options.slient)) {
      each(_slient, function (value, key) {
        value = options.slient[key];
        if (isDefined(value)) {
          _slient[key] = value;
        }
      });
    }
    if (isObject(options.report)) {
      each(_report, function (value, key) {
        value = options.report[key];
        if (isDefined(value)) {
          _report[key] = value;
        }
      });
    }
  }

  function report(messages, type) {
    if (logOptions.space && logOptions.token) {
      _console.error(messages, type);  //TODO
    }
  }

  function logci(obj) {
    if (isFunction(obj)) {
      try {
        obj();
      } catch (error) {
        logci.error(err, 'error');
      }
    } else if (isObject(obj)) {
      setOptions(obj)
    }
  }

  each(['log', 'info', 'warn', 'error'], function (method) {
    _console[method] = isFunction(_console[method]) ? _console[method] : noop;
    _slient[method] = false;
    _report[method] = false;
    logci[method] = function () {
      if (!_slient[method]) {
        _console[method].apply(_console, arguments);
      }
      if (_report[method] && arguments[0]) {
        report(arguments[0], isString(arguments[1]) ? arguments[1] : method);
      }
    };
  });
  _report.error = true;

  if (typeof module === 'object' && module.exports) {
    module.exports = logci;
  } else if (typeof define === 'function' && define.amd) {
    define(function () {
      return logci;
    });
  }
  if (typeof window === 'object') {
    window.logci = logci;
  }
})();
<|endoftext|>


<commit_before>window.onload = function() {
   loadOptions();
   updateTime();
};

var USER_OPTIONS = JSON.parse(localStorage.getItem('userOptions'));
var comLinks = {
   'r':'https://www.reddit.com/r/',
   'g':'https://www.google.com/search?q=',
   'y':'https://www.youtube.com/results?search_query=',
   'a':'http://smile.amazon.com/s?url=search-alias%3Daps&field-keywords=',
   'w':'https://www.wikipedia.org/w/index.php?title=Special:Search&search=',
   'wa':'http://www.wolframalpha.com/input/?i=',
   'imdb':'https://www.imdb.com/find?s=all&q=',
   't':'',
}

function interpret() {
   inputElem = document.getElementById('commandInput');
   inputElem.select();
   var input = inputElem.value;
   if (input == '') { return; }

   // Check for available commands
   if (input.trim() === 'help') {
      displayHelp();
      return;
   } else if (input.trim() === 'options') {
      displayOptions();
      return;
   }

   // Parse input
   var inputArray = input.split(';');
   var nt;
   if (inputArray[inputArray.length-1] === 'n' || USER_OPTIONS.alwaysNewTab) {
      nt = true;
   } else {
      nt = false;
   }
   switch(inputArray.length) {
      case 1:
         command = USER_OPTIONS.defaultCommand;
         query = inputArray[0].trim();
         break;
      case 2:
         if (inputArray[inputArray.length-1] !== 'n') {
            command = inputArray[0].trim();
            query = inputArray[1].trim();
            break;
         } else {
            command = USER_OPTIONS.defaultCommand;
            query = inputArray[0];
            break;
         }
      case 3:
         command = inputArray[0].trim();
         query = inputArray[1].trim();
         // Assume inputArray[2] is new tab flag
         break;
      default:
         displayText('unable to interpret');
   }
   if (command === 'w') { // Wikipedia fix
      query = query.replace(/ /g,'+'); // replace all spaces with +'s
   } else {
      query = encodeURIComponent(query);
   }
   if (comLinks.hasOwnProperty(command)) {
      goToSite(comLinks[command] + query, nt);
      return false;
   } else {
      displayText('command not recognized');
      return;
   }
}

function verifyKey(e) {
   var keycode;
   if (window.event) {
      keycode = window.event.keyCode;
   } else if (e) {
      keycode = e.which;
   }
   if (keycode == 13) { // Enter/return key
      clearText();
      interpret();
   }
   updateInputLength();
}

function updateInputLength() {
   var input = document.getElementById('commandInput');
   if (input.value.length >= (input.size - 1)) {
      input.size = input.value.length + 1;
   }
}

function goToSite(url, nt) {
   if (!url.startsWith('http')) {
      url = 'https://'+url;
   }
   if (nt) {
      var win = window.open(url);
      win.focus();
      return false;
   } else {
      window.location.replace(url);
      return false;
   }
}

function displayText(string) {
   var div = document.getElementById('text_div');
   clearText();
   div.innerHTML += '
'+string+'
';
}

function clearText() {
   document.getElementById('text_div').innerHTML = '';
}

function applyBgColor(c) {
   document.body.style.backgroundColor = c;
   //document.getElementById('commandInput').style.backgroundColor = c;
}

function saveOptions() {
   if (typeof(Storage) !== "undefined") {
      // Default command
      var defaultCommandRadios = document.getElementById('defaultCommandForm');
      var defaultCommand = null;
      for (var i=0; i < defaultCommandRadios.length; i++) {
         if (defaultCommandRadios[i].checked) {
            defaultCommand = defaultCommandRadios[i].value;
            break;
         }
      }
      if (defaultCommand !== null) {
         USER_OPTIONS.defaultCommand = defaultCommand;
      }

      // Tab open style
      var alwaysNewTab = document.getElementById('alwaysNewTabCheckbox').checked;
      USER_OPTIONS.alwaysNewTab = alwaysNewTab;

      // Background color
      var bgColor = document.getElementById('bgColorInput').value;
            // check if valid hex value
      if (/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(bgColor)) {
         USER_OPTIONS.bgColor = bgColor;
         applyBgColor(bgColor);

         // Store prefs
         localStorage.setItem('userOptions', JSON.stringify(USER_OPTIONS));
         document.getElementById('optionsSubText').innerHTML = 'settings saved';
      } else {
         document.getElementById('optionsSubText').innerHTML = 'not a valid color';
      }

   } else {
      alert("Browser does not support local storage: your settings won't be saved (sorry)");
   }
}

function loadOptions() {
   if (typeof(Storage) !== "undefined") {
      if (localStorage.getItem('userOptions') !== null) { // Load options
         var userOptions = localStorage.getItem('userOptions');
         userOptions = JSON.parse(userOptions);
         USER_OPTIONS = userOptions;
         applyBgColor(USER_OPTIONS.bgColor);
         return userOptions;
      } else { // Create defaults
         var options = {
            "defaultCommand": "g",
            "alwaysNewTab": false,
            "bgColor": "#A1C0C0"
         };
         localStorage.setItem('userOptions', JSON.stringify(options));
      }
   }
}

function displayOptions() {
   var optionsHTML =
      `

         Default Command (command that executes if no command was specified)

            <form id='defaultCommandForm'>
               <input type='radio' name='defaultCommandRadio' value='t'>Go to website

               <input type='radio' name='defaultCommandRadio' value='g'>Google search

               <input type='radio' name='defaultCommandRadio' value='w'>Wikipedia search

               <input type='radio' name='defaultCommandRadio' value='y'>YouTube search

               <input type='radio' name='defaultCommandRadio' value='a'>Amazon search

               <input type='radio' name='defaultCommandRadio' value='imdb'>IMDB search

               <input type='radio' name='defaultCommandRadio' value='wa'>Wolfram Alpha search

               <input type='radio' name='defaultCommandRadio' value='r'>Go to subreddit
            </form>

         Open Style

            <input type='checkbox' id='alwaysNewTabCheckbox' value='newTab'>Always open in new tab

         Background Color

            Color: <input type='text' id='bgColorInput' placeholder='#A1C0C0' size='7' spellcheck='false'>
            Color Picker

            <button type='button' id='saveOptionsBtn'>Save</button>

      `
   document.getElementById('text_div').innerHTML = optionsHTML;
   document.getElementById('saveOptionsBtn').onclick = saveOptions;

   // Show saved options
   var defaultCommandRadios = document.getElementById('defaultCommandForm');
   for (var i=0; i < defaultCommandRadios.length; i++) {
      if (USER_OPTIONS.defaultCommand === defaultCommandRadios[i].value) {
         defaultCommandRadios[i].checked = true;
      }
   }
   document.getElementById('alwaysNewTabCheckbox').checked = USER_OPTIONS.alwaysNewTab;
   document.getElementById('bgColorInput').value = USER_OPTIONS.bgColor;
}

function displayHelp() {
   var helpHTML =
      `

syntax: command;query[;n]

            Command
            Description

            options
            show options menu

            r;&ltsubreddit&gt
            go to subreddit

            g;&ltquery&gt
            google search

            y;&ltquery&gt
            youtube search

            a;&ltquery&gt
            amazon search

            w;&ltquery&gt
            wikipedia search

            imdb;&ltquery&gt
            imdb search

            wa;&ltquery&gt
            wolfram alpha search

            t;&lturl&gt
            open url in current tab

            &ltcommand&gt;n
            open action in new tab

            help
            show this text

`
   document.getElementById('text_div').innerHTML = helpHTML;
}

function checkTime(i) {
   if (i < 10) { i = '0' + i };
   if (i == 0) { i = '12' };
   return i;
}
function updateTime() {
   var d = new Date();
   var h = d.getHours(); if (h > 12) { h -= 12; }; h = checkTime(h);
   var m = checkTime(d.getMinutes());
   document.getElementById('time_div').innerHTML = "
"+h+':'+m+'
';
   var t = setTimeout(updateTime, 5000);
}
<commit_msg>fixed options not loading just after creation<commit_after>window.onload = function() {
   loadOptions();
   updateTime();
};

var USER_OPTIONS = JSON.parse(localStorage.getItem('userOptions'));
var comLinks = {
   'r':'https://www.reddit.com/r/',
   'g':'https://www.google.com/search?q=',
   'y':'https://www.youtube.com/results?search_query=',
   'a':'http://smile.amazon.com/s?url=search-alias%3Daps&field-keywords=',
   'w':'https://www.wikipedia.org/w/index.php?title=Special:Search&search=',
   'wa':'http://www.wolframalpha.com/input/?i=',
   'imdb':'https://www.imdb.com/find?s=all&q=',
   't':'',
}

function interpret() {
   inputElem = document.getElementById('commandInput');
   inputElem.select();
   var input = inputElem.value;
   if (input == '') { return; }

   // Check for available commands
   if (input.trim() === 'help') {
      displayHelp();
      return;
   } else if (input.trim() === 'options') {
      displayOptions();
      return;
   }

   // Parse input
   var inputArray = input.split(';');
   var nt;
   if (inputArray[inputArray.length-1] === 'n' || USER_OPTIONS.alwaysNewTab) {
      nt = true;
   } else {
      nt = false;
   }
   switch(inputArray.length) {
      case 1:
         command = USER_OPTIONS.defaultCommand;
         query = inputArray[0].trim();
         break;
      case 2:
         if (inputArray[inputArray.length-1] !== 'n') {
            command = inputArray[0].trim();
            query = inputArray[1].trim();
            break;
         } else {
            command = USER_OPTIONS.defaultCommand;
            query = inputArray[0];
            break;
         }
      case 3:
         command = inputArray[0].trim();
         query = inputArray[1].trim();
         // Assume inputArray[2] is new tab flag
         break;
      default:
         displayText('unable to interpret');
   }
   if (command === 'w') { // Wikipedia fix
      query = query.replace(/ /g,'+'); // replace all spaces with +'s
   } else {
      query = encodeURIComponent(query);
   }
   if (comLinks.hasOwnProperty(command)) {
      goToSite(comLinks[command] + query, nt);
      return false;
   } else {
      displayText('command not recognized');
      return;
   }
}

function verifyKey(e) {
   var keycode;
   if (window.event) {
      keycode = window.event.keyCode;
   } else if (e) {
      keycode = e.which;
   }
   if (keycode == 13) { // Enter/return key
      clearText();
      interpret();
   }
   updateInputLength();
}

function updateInputLength() {
   var input = document.getElementById('commandInput');
   if (input.value.length >= (input.size - 1)) {
      input.size = input.value.length + 1;
   }
}

function goToSite(url, nt) {
   if (!url.startsWith('http')) {
      url = 'https://'+url;
   }
   if (nt) {
      var win = window.open(url);
      win.focus();
      return false;
   } else {
      window.location.replace(url);
      return false;
   }
}

function displayText(string) {
   var div = document.getElementById('text_div');
   clearText();
   div.innerHTML += '
'+string+'
';
}

function clearText() {
   document.getElementById('text_div').innerHTML = '';
}

function applyBgColor(c) {
   document.body.style.backgroundColor = c;
   //document.getElementById('commandInput').style.backgroundColor = c;
}

function saveOptions() {
   if (typeof(Storage) !== "undefined") {
      // Default command
      var defaultCommandRadios = document.getElementById('defaultCommandForm');
      var defaultCommand = null;
      for (var i=0; i < defaultCommandRadios.length; i++) {
         if (defaultCommandRadios[i].checked) {
            defaultCommand = defaultCommandRadios[i].value;
            break;
         }
      }
      if (defaultCommand !== null) {
         USER_OPTIONS.defaultCommand = defaultCommand;
      }

      // Tab open style
      var alwaysNewTab = document.getElementById('alwaysNewTabCheckbox').checked;
      USER_OPTIONS.alwaysNewTab = alwaysNewTab;

      // Background color
      var bgColor = document.getElementById('bgColorInput').value;
            // check if valid hex value
      if (/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(bgColor)) {
         USER_OPTIONS.bgColor = bgColor;
         applyBgColor(bgColor);

         // Store prefs
         localStorage.setItem('userOptions', JSON.stringify(USER_OPTIONS));
         document.getElementById('optionsSubText').innerHTML = 'settings saved';
      } else {
         document.getElementById('optionsSubText').innerHTML = 'not a valid color';
      }

   } else {
      alert("Browser does not support local storage: your settings won't be saved (sorry)");
   }
}

function loadOptions() {
   if (typeof(Storage) !== "undefined") {
      if (localStorage.getItem('userOptions') !== null) { // Load options
         var userOptions = localStorage.getItem('userOptions');
         userOptions = JSON.parse(userOptions);
         USER_OPTIONS = userOptions;
         applyBgColor(USER_OPTIONS.bgColor);
         return userOptions;
      } else { // Create defaults
         var options = {
            "defaultCommand": "g",
            "alwaysNewTab": false,
            "bgColor": "#A1C0C0"
         };
         localStorage.setItem('userOptions', JSON.stringify(options));
         userOptions = localStorage.getItem('userOptions');
         USER_OPTIONS = JSON.parse(userOptions);
      }
   }
}

function displayOptions() {
   var optionsHTML =
      `

         Default Command (command that executes if no command was specified)

            <form id='defaultCommandForm'>
               <input type='radio' name='defaultCommandRadio' value='t'>Go to website

               <input type='radio' name='defaultCommandRadio' value='g'>Google search

               <input type='radio' name='defaultCommandRadio' value='w'>Wikipedia search

               <input type='radio' name='defaultCommandRadio' value='y'>YouTube search

               <input type='radio' name='defaultCommandRadio' value='a'>Amazon search

               <input type='radio' name='defaultCommandRadio' value='imdb'>IMDB search

               <input type='radio' name='defaultCommandRadio' value='wa'>Wolfram Alpha search

               <input type='radio' name='defaultCommandRadio' value='r'>Go to subreddit
            </form>

         Open Style

            <input type='checkbox' id='alwaysNewTabCheckbox' value='newTab'>Always open in new tab

         Background Color

            Color: <input type='text' id='bgColorInput' placeholder='#A1C0C0' size='7' spellcheck='false'>
            Color Picker

            <button type='button' id='saveOptionsBtn'>Save</button>

      `
   document.getElementById('text_div').innerHTML = optionsHTML;
   document.getElementById('saveOptionsBtn').onclick = saveOptions;

   // Display saved options
   if (localStorage.getItem('userOptions') !== null) {
      displaySavedOptions();
   } else {
      loadOptions();
      displaySavedOptions();
   }
}

function displaySavedOptions() {
   var defaultCommandRadios = document.getElementById('defaultCommandForm');
   for (var i=0; i < defaultCommandRadios.length; i++) {
      if (USER_OPTIONS.defaultCommand === defaultCommandRadios[i].value) {
         defaultCommandRadios[i].checked = true;
      }
   }
   document.getElementById('alwaysNewTabCheckbox').checked = USER_OPTIONS.alwaysNewTab;
   document.getElementById('bgColorInput').value = USER_OPTIONS.bgColor;
}

function displayHelp() {
   var helpHTML =
      `

syntax: command;query[;n]

            Command
            Description

            options
            show options menu

            r;&ltsubreddit&gt
            go to subreddit

            g;&ltquery&gt
            google search

            y;&ltquery&gt
            youtube search

            a;&ltquery&gt
            amazon search

            w;&ltquery&gt
            wikipedia search

            imdb;&ltquery&gt
            imdb search

            wa;&ltquery&gt
            wolfram alpha search

            t;&lturl&gt
            open url in current tab

            &ltcommand&gt;n
            open action in new tab

            help
            show this text

`
   document.getElementById('text_div').innerHTML = helpHTML;
}

function checkTime(i) {
   if (i < 10) { i = '0' + i };
   if (i == 0) { i = '12' };
   return i;
}
function updateTime() {
   var d = new Date();
   var h = d.getHours(); if (h > 12) { h -= 12; }; h = checkTime(h);
   var m = checkTime(d.getMinutes());
   document.getElementById('time_div').innerHTML = "
"+h+':'+m+'
';
   var t = setTimeout(updateTime, 5000);
}
<|endoftext|>


<commit_before>window.onload = function() {
   loadOptions();
   updateTime();
   document.getElementById('fixedHelpBtn').addEventListener('click', fixedHelpBtnCB);
   document.getElementById('fixedOptionsBtn').addEventListener('click', fixedOptionsBtnCB);
};

var USER_OPTIONS = JSON.parse(localStorage.getItem('userOptions'));
var comLinks = {
   'r':'https://www.reddit.com/r/',
   'g':'https://www.google.com/search?q=',
   'y':'https://www.youtube.com/results?search_query=',
   'a':'http://smile.amazon.com/s?url=search-alias%3Daps&field-keywords=',
   'w':'https://www.wikipedia.org/w/index.php?title=Special:Search&search=',
   'wa':'http://www.wolframalpha.com/input/?i=',
   'imdb':'https://www.imdb.com/find?s=all&q=',
   'img':'https://www.google.com/search?tbm=isch&q=',
   't':'',
}

function interpret() {
   inputElem = document.getElementById('commandInput');
   inputElem.select();
   var input = inputElem.value;
   if (input == '') { return; }

   // Check for available commands
   if (input.trim() === 'help' || input.trim() === '?') {
      displayHelp();
      return;
   } else if (input.trim() === 'options') {
      displayOptions();
      return;
   }

   // Parse input
   var inputArray = input.split(';');
   var nt;
   if (inputArray[inputArray.length-1] === 'n' || USER_OPTIONS.alwaysNewTab) {
      nt = true;
   } else {
      nt = false;
   }
   switch(inputArray.length) {
      case 1:
         command = USER_OPTIONS.defaultCommand;
         query = inputArray[0].trim();
         break;
      case 2:
         if (inputArray[inputArray.length-1] !== 'n') {
            command = inputArray[0].trim();
            query = inputArray[1].trim();
            break;
         } else {
            command = USER_OPTIONS.defaultCommand;
            query = inputArray[0];
            break;
         }
      case 3:
         command = inputArray[0].trim();
         query = inputArray[1].trim();
         // Assume inputArray[2] is new tab flag
         break;
      default:
         displayText('unable to interpret');
   }
   if (command === 'w') {        // Wikipedia fix
      query = query.replace(/ /g,'+'); // replace all spaces with +'s
   } else if (command === 'r') { // Reddit fix
      // Don't encode, allowing for adding of url parameters e.g. /top?t=month
   } else {
      query = encodeURIComponent(query);
   }
   if (comLinks.hasOwnProperty(command)) {
      goToSite(comLinks[command] + query, nt);
      return false;
   } else {
      displayText('command not recognized');
      return;
   }
}

function verifyKey(e) {
   var keycode;
   if (window.event) {
      keycode = window.event.keyCode;
   } else if (e) {
      keycode = e.which;
   }
   if (keycode == 13) { // Enter/return key
      clearTextDiv();
      interpret();
   }
   updateInputLength();
}

function updateInputLength() {
   var input = document.getElementById('commandInput');
   if (input.value.length >= (input.size - 1)) {
      input.size = input.value.length + 1;
   }
}

function goToSite(url, nt) {
   if (!url.startsWith('http')) {
      url = 'https://'+url;
   }
   if (nt) {
      var win = window.open(url);
      win.focus();
      return false;
   } else {
      window.location.href = url;
      return false;
   }
}

function displayText(string) {
   var div = document.getElementById('text_div');
   clearTextDiv();
   div.innerHTML += '
'+string+'
';
}

function clearTextDiv() {
   document.getElementById('text_div').innerHTML = '';
}

function setBgColor(c) {
   document.body.style.backgroundColor = c;
}

function saveOptionsBtnCB() {
   if (typeof(Storage) !== "undefined") {
      // Default command
      var defaultCommandRadios = document.getElementById('defaultCommandForm');
      var defaultCommand = null;
      for (var i=0; i < defaultCommandRadios.length; i++) {
         if (defaultCommandRadios[i].checked) {
            defaultCommand = defaultCommandRadios[i].value;
            break;
         }
      }
      if (defaultCommand !== null) {
         USER_OPTIONS.defaultCommand = defaultCommand;
      }

      // Tab open style
      var alwaysNewTab = document.getElementById('alwaysNewTabCheckbox').checked;
      USER_OPTIONS.alwaysNewTab = alwaysNewTab;

      // Background color
      var bgColor = document.getElementById('bgColorInput').value;
            // check if valid hex value
      if (/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(bgColor)) {
         USER_OPTIONS.bgColor = bgColor;
         setBgColor(bgColor);

         // Store prefs
         localStorage.setItem('userOptions', JSON.stringify(USER_OPTIONS));
         document.getElementById('optionsSubText').innerHTML = 'settings saved';
      } else {
         document.getElementById('optionsSubText').innerHTML = 'not a valid color';
      }

   } else {
      alert("Browser does not support local storage: your settings won't be saved (sorry)");
   }
   clearTextDiv();
   comInput = document.getElementById('commandInput');
   comInput.value = '';
   comInput.select();
}

function loadOptions() {
   if (typeof(Storage) !== "undefined") {
      if (localStorage.getItem('userOptions') !== null) { // Load options
         var userOptions = localStorage.getItem('userOptions');
         userOptions = JSON.parse(userOptions);
         USER_OPTIONS = userOptions;
         setBgColor(USER_OPTIONS.bgColor);
         return userOptions;
      } else { // Create defaults
         var options = {
            "defaultCommand": "g",
            "alwaysNewTab": false,
            "bgColor": "#A1C0C0"
         };
         localStorage.setItem('userOptions', JSON.stringify(options));
         userOptions = localStorage.getItem('userOptions');
         USER_OPTIONS = JSON.parse(userOptions);
      }
   }
}

function displayOptions() {
   var optionsHTML =
      `

         Default Command (command that executes if no command was specified)

            <form id='defaultCommandForm'>
               <input type='radio' name='defaultCommandRadio' value='t'>Go to website

               <input type='radio' name='defaultCommandRadio' value='g'>Google search

               <input type='radio' name='defaultCommandRadio' value='w'>Wikipedia search

               <input type='radio' name='defaultCommandRadio' value='y'>YouTube search

               <input type='radio' name='defaultCommandRadio' value='a'>Amazon search

               <input type='radio' name='defaultCommandRadio' value='imdb'>IMDB search

               <input type='radio' name='defaultCommandRadio' value='img'>Google Images search

               <input type='radio' name='defaultCommandRadio' value='wa'>Wolfram Alpha search

               <input type='radio' name='defaultCommandRadio' value='r'>Go to subreddit
            </form>

         Open Style

            <input type='checkbox' id='alwaysNewTabCheckbox' value='newTab'>Always open in new tab

         Background Color

            Color: <input type='text' id='bgColorInput' placeholder='#A1C0C0' size='7' spellcheck='false'>
            Color Picker

            <button type='button' id='saveOptionsBtn'>Done</button>

      `
   document.getElementById('text_div').innerHTML = optionsHTML;
   document.getElementById('saveOptionsBtn').onclick = saveOptionsBtnCB;

   // Display saved options
   if (localStorage.getItem('userOptions') !== null) {
      displaySavedOptions();
   } else {
      loadOptions();
      displaySavedOptions();
   }
}

function displaySavedOptions() {
   var defaultCommandRadios = document.getElementById('defaultCommandForm');
   for (var i=0; i < defaultCommandRadios.length; i++) {
      if (USER_OPTIONS.defaultCommand === defaultCommandRadios[i].value) {
         defaultCommandRadios[i].checked = true;
      }
   }
   document.getElementById('alwaysNewTabCheckbox').checked = USER_OPTIONS.alwaysNewTab;
   document.getElementById('bgColorInput').value = USER_OPTIONS.bgColor;
}

function displayHelp() {
   var helpHTML =
      `
syntax:
command;query[;n]

            Command
            Description

            options
            show options menu

            r;&ltsubreddit&gt
            go to subreddit

            g;&ltquery&gt
            google search

            y;&ltquery&gt
            youtube search

            a;&ltquery&gt
            amazon search

            w;&ltquery&gt
            wikipedia search

            imdb;&ltquery&gt
            imdb search

            img;&ltquery&gt
            google images search

            wa;&ltquery&gt
            wolfram alpha search

            t;&lturl&gt
            open url in current tab

            &ltcommand&gt;n
            open action in new tab

            help
            show this text

`
   document.getElementById('text_div').innerHTML = helpHTML;
}

function fixedHelpBtnCB() {
   input = document.getElementById('commandInput');
   input.value = 'help';
   input.select();
   displayHelp();
}

function fixedOptionsBtnCB() {
   input = document.getElementById('commandInput');
   input.value = 'options';
   input.select();
   displayOptions();
}

function checkTime(i) {
   if (i < 10) { i = '0' + i };
   if (i == 0) { i = '12' };
   return i;
}
function updateTime() {
   var d = new Date();
   var h = d.getHours(); if (h > 12) { h -= 12; }; h = checkTime(h);
   var m = checkTime(d.getMinutes());
   document.getElementById('time_div').innerHTML = "
"+h+':'+m+'
';
   var t = setTimeout(updateTime, 5000);
}
<commit_msg>Update help table<commit_after>window.onload = function() {
   loadOptions();
   updateTime();
   document.getElementById('fixedHelpBtn').addEventListener('click', fixedHelpBtnCB);
   document.getElementById('fixedOptionsBtn').addEventListener('click', fixedOptionsBtnCB);
};

var USER_OPTIONS = JSON.parse(localStorage.getItem('userOptions'));
var comLinks = {
   'r':'https://www.reddit.com/r/',
   'g':'https://www.google.com/search?q=',
   'y':'https://www.youtube.com/results?search_query=',
   'a':'http://smile.amazon.com/s?url=search-alias%3Daps&field-keywords=',
   'w':'https://www.wikipedia.org/w/index.php?title=Special:Search&search=',
   'wa':'http://www.wolframalpha.com/input/?i=',
   'imdb':'https://www.imdb.com/find?s=all&q=',
   'img':'https://www.google.com/search?tbm=isch&q=',
   't':'',
}

function interpret() {
   inputElem = document.getElementById('commandInput');
   inputElem.select();
   var input = inputElem.value;
   if (input == '') { return; }

   // Check for available commands
   if (input.trim() === 'help' || input.trim() === '?') {
      displayHelp();
      return;
   } else if (input.trim() === 'options') {
      displayOptions();
      return;
   }

   // Parse input
   var inputArray = input.split(';');
   var nt;
   if (inputArray[inputArray.length-1] === 'n' || USER_OPTIONS.alwaysNewTab) {
      nt = true;
   } else {
      nt = false;
   }
   switch(inputArray.length) {
      case 1:
         command = USER_OPTIONS.defaultCommand;
         query = inputArray[0].trim();
         break;
      case 2:
         if (inputArray[inputArray.length-1] !== 'n') {
            command = inputArray[0].trim();
            query = inputArray[1].trim();
            break;
         } else {
            command = USER_OPTIONS.defaultCommand;
            query = inputArray[0];
            break;
         }
      case 3:
         command = inputArray[0].trim();
         query = inputArray[1].trim();
         // Assume inputArray[2] is new tab flag
         break;
      default:
         displayText('unable to interpret');
   }
   if (command === 'w') {        // Wikipedia fix
      query = query.replace(/ /g,'+'); // replace all spaces with +'s
   } else if (command === 'r') { // Reddit fix
      // Don't encode, allowing for adding of url parameters e.g. /top?t=month
   } else {
      query = encodeURIComponent(query);
   }
   if (comLinks.hasOwnProperty(command)) {
      goToSite(comLinks[command] + query, nt);
      return false;
   } else {
      displayText('command not recognized');
      return;
   }
}

function verifyKey(e) {
   var keycode;
   if (window.event) {
      keycode = window.event.keyCode;
   } else if (e) {
      keycode = e.which;
   }
   if (keycode == 13) { // Enter/return key
      clearTextDiv();
      interpret();
   }
   updateInputLength();
}

function updateInputLength() {
   var input = document.getElementById('commandInput');
   if (input.value.length >= (input.size - 1)) {
      input.size = input.value.length + 1;
   }
}

function goToSite(url, nt) {
   if (!url.startsWith('http')) {
      url = 'https://'+url;
   }
   if (nt) {
      var win = window.open(url);
      win.focus();
      return false;
   } else {
      window.location.href = url;
      return false;
   }
}

function displayText(string) {
   var div = document.getElementById('text_div');
   clearTextDiv();
   div.innerHTML += '
'+string+'
';
}

function clearTextDiv() {
   document.getElementById('text_div').innerHTML = '';
}

function setBgColor(c) {
   document.body.style.backgroundColor = c;
}

function saveOptionsBtnCB() {
   if (typeof(Storage) !== "undefined") {
      // Default command
      var defaultCommandRadios = document.getElementById('defaultCommandForm');
      var defaultCommand = null;
      for (var i=0; i < defaultCommandRadios.length; i++) {
         if (defaultCommandRadios[i].checked) {
            defaultCommand = defaultCommandRadios[i].value;
            break;
         }
      }
      if (defaultCommand !== null) {
         USER_OPTIONS.defaultCommand = defaultCommand;
      }

      // Tab open style
      var alwaysNewTab = document.getElementById('alwaysNewTabCheckbox').checked;
      USER_OPTIONS.alwaysNewTab = alwaysNewTab;

      // Background color
      var bgColor = document.getElementById('bgColorInput').value;
            // check if valid hex value
      if (/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(bgColor)) {
         USER_OPTIONS.bgColor = bgColor;
         setBgColor(bgColor);

         // Store prefs
         localStorage.setItem('userOptions', JSON.stringify(USER_OPTIONS));
         document.getElementById('optionsSubText').innerHTML = 'settings saved';
      } else {
         document.getElementById('optionsSubText').innerHTML = 'not a valid color';
      }

   } else {
      alert("Browser does not support local storage: your settings won't be saved (sorry)");
   }
   clearTextDiv();
   comInput = document.getElementById('commandInput');
   comInput.value = '';
   comInput.select();
}

function loadOptions() {
   if (typeof(Storage) !== "undefined") {
      if (localStorage.getItem('userOptions') !== null) { // Load options
         var userOptions = localStorage.getItem('userOptions');
         userOptions = JSON.parse(userOptions);
         USER_OPTIONS = userOptions;
         setBgColor(USER_OPTIONS.bgColor);
         return userOptions;
      } else { // Create defaults
         var options = {
            "defaultCommand": "g",
            "alwaysNewTab": false,
            "bgColor": "#A1C0C0"
         };
         localStorage.setItem('userOptions', JSON.stringify(options));
         userOptions = localStorage.getItem('userOptions');
         USER_OPTIONS = JSON.parse(userOptions);
      }
   }
}

function displayOptions() {
   var optionsHTML =
      `

         Default Command (command that executes if no command was specified)

            <form id='defaultCommandForm'>
               <input type='radio' name='defaultCommandRadio' value='t'>Go to website

               <input type='radio' name='defaultCommandRadio' value='g'>Google search

               <input type='radio' name='defaultCommandRadio' value='w'>Wikipedia search

               <input type='radio' name='defaultCommandRadio' value='y'>YouTube search

               <input type='radio' name='defaultCommandRadio' value='a'>Amazon search

               <input type='radio' name='defaultCommandRadio' value='imdb'>IMDB search

               <input type='radio' name='defaultCommandRadio' value='img'>Google Images search

               <input type='radio' name='defaultCommandRadio' value='wa'>Wolfram Alpha search

               <input type='radio' name='defaultCommandRadio' value='r'>Go to subreddit
            </form>

         Open Style

            <input type='checkbox' id='alwaysNewTabCheckbox' value='newTab'>Always open in new tab

         Background Color

            Color: <input type='text' id='bgColorInput' placeholder='#A1C0C0' size='7' spellcheck='false'>
            Color Picker

            <button type='button' id='saveOptionsBtn'>Done</button>

      `
   document.getElementById('text_div').innerHTML = optionsHTML;
   document.getElementById('saveOptionsBtn').onclick = saveOptionsBtnCB;

   // Display saved options
   if (localStorage.getItem('userOptions') !== null) {
      displaySavedOptions();
   } else {
      loadOptions();
      displaySavedOptions();
   }
}

function displaySavedOptions() {
   var defaultCommandRadios = document.getElementById('defaultCommandForm');
   for (var i=0; i < defaultCommandRadios.length; i++) {
      if (USER_OPTIONS.defaultCommand === defaultCommandRadios[i].value) {
         defaultCommandRadios[i].checked = true;
      }
   }
   document.getElementById('alwaysNewTabCheckbox').checked = USER_OPTIONS.alwaysNewTab;
   document.getElementById('bgColorInput').value = USER_OPTIONS.bgColor;
}

function displayHelp() {
   var helpHTML =
      `
syntax:
command;query[;n]

            Command
            Description

            options
            show options menu

            r;&ltsubreddit&gt
            go to subreddit

            g;&ltquery&gt
            google search

            y;&ltquery&gt
            youtube search

            a;&ltquery&gt
            amazon search

            w;&ltquery&gt
            wikipedia search

            imdb;&ltquery&gt
            imdb search

            img;&ltquery&gt
            google images search

            wa;&ltquery&gt
            wolfram alpha search

            t;&lturl&gt
            open url in current tab

            &ltcommand&gt;n
            open action in new tab

            help | ?
            show this text

`
   document.getElementById('text_div').innerHTML = helpHTML;
}

function fixedHelpBtnCB() {
   input = document.getElementById('commandInput');
   input.value = 'help';
   input.select();
   displayHelp();
}

function fixedOptionsBtnCB() {
   input = document.getElementById('commandInput');
   input.value = 'options';
   input.select();
   displayOptions();
}

function checkTime(i) {
   if (i < 10) { i = '0' + i };
   if (i == 0) { i = '12' };
   return i;
}
function updateTime() {
   var d = new Date();
   var h = d.getHours(); if (h > 12) { h -= 12; }; h = checkTime(h);
   var m = checkTime(d.getMinutes());
   document.getElementById('time_div').innerHTML = "
"+h+':'+m+'
';
   var t = setTimeout(updateTime, 5000);
}
<|endoftext|>


<commit_before>/**
 * Image.js
 *
 * Copyright 2013, Moxiecode Systems AB
 * Released under GPL License.
 *
 * License: http://www.plupload.com/license
 * Contributing: http://www.plupload.com/contributing
 */

/*jshint smarttabs:true, undef:true, unused:true, latedef:true, curly:true, bitwise:true, scripturl:true, browser:true, laxcomma:true */
/*global define:true */

/**
@class moxie/runtime/flash/image/Image
@private
*/
define("moxie/runtime/flash/image/Image", [
	"moxie/runtime/flash/Runtime",
	"moxie/core/utils/Basic",
	"moxie/runtime/Transporter",
	"moxie/file/Blob",
	"moxie/file/FileReaderSync"
], function(extensions, Basic, Transporter, Blob, FileReaderSync) {

	var Image = {
		loadFromBlob: function(blob) {
			var comp = this, self = comp.getRuntime();

			function exec(srcBlob) {
				self.shimExec.call(comp, 'Image', 'loadFromBlob', srcBlob.uid);
				comp = self = null;
			}

			if (blob.isDetached()) { // binary string
				var tr = new Transporter();
				tr.bind("TransportingComplete", function() {
					exec(tr.result.getSource());
				});
				tr.transport(blob.getSource(), blob.type, self.uid);
			} else {
				exec(blob.getSource());
			}
		},

		loadFromImage: function(img) {
			var self = this.getRuntime();
			return self.shimExec.call(this, 'Image', 'loadFromImage', img.uid);
		},

		getAsBlob: function(type, quality) {
			var self = this.getRuntime()
			, blob = self.shimExec.call(this, 'Image', 'getAsBlob', type, quality)
			;
			if (blob) {
				return new Blob(self.uid, blob);
			}
			return null;
		},

		getAsDataURL: function() {
			var self = this.getRuntime()
			, blob = self.Image.getAsBlob.apply(this, arguments)
			, frs
			;
			if (!blob) {
				return null;
			}
			frs = new FileReaderSync();
			return frs.readAsDataURL(blob);
		}
	};

	return (extensions.Image = Image);
});<commit_msg>Image, Flash: Properly pass runtime uid to Transporter.<commit_after>/**
 * Image.js
 *
 * Copyright 2013, Moxiecode Systems AB
 * Released under GPL License.
 *
 * License: http://www.plupload.com/license
 * Contributing: http://www.plupload.com/contributing
 */

/*jshint smarttabs:true, undef:true, unused:true, latedef:true, curly:true, bitwise:true, scripturl:true, browser:true, laxcomma:true */
/*global define:true */

/**
@class moxie/runtime/flash/image/Image
@private
*/
define("moxie/runtime/flash/image/Image", [
	"moxie/runtime/flash/Runtime",
	"moxie/core/utils/Basic",
	"moxie/runtime/Transporter",
	"moxie/file/Blob",
	"moxie/file/FileReaderSync"
], function(extensions, Basic, Transporter, Blob, FileReaderSync) {

	var Image = {
		loadFromBlob: function(blob) {
			var comp = this, self = comp.getRuntime();

			function exec(srcBlob) {
				self.shimExec.call(comp, 'Image', 'loadFromBlob', srcBlob.uid);
				comp = self = null;
			}

			if (blob.isDetached()) { // binary string
				var tr = new Transporter();
				tr.bind("TransportingComplete", function() {
					exec(tr.result.getSource());
				});
				tr.transport(blob.getSource(), blob.type, { ruid: self.uid });
			} else {
				exec(blob.getSource());
			}
		},

		loadFromImage: function(img) {
			var self = this.getRuntime();
			return self.shimExec.call(this, 'Image', 'loadFromImage', img.uid);
		},

		getAsBlob: function(type, quality) {
			var self = this.getRuntime()
			, blob = self.shimExec.call(this, 'Image', 'getAsBlob', type, quality)
			;
			if (blob) {
				return new Blob(self.uid, blob);
			}
			return null;
		},

		getAsDataURL: function() {
			var self = this.getRuntime()
			, blob = self.Image.getAsBlob.apply(this, arguments)
			, frs
			;
			if (!blob) {
				return null;
			}
			frs = new FileReaderSync();
			return frs.readAsDataURL(blob);
		}
	};

	return (extensions.Image = Image);
});<|endoftext|>