Seleccionar y soltar archivos y / o carpetas para analizar

He usado una parte de una publicación aquí en SO (aunque no lo recuerdo) para analizar archivos y carpetas en Chrome, pero no puedo hacer que funcione en Firefox (y para ser sincero, no lo he probado otros, aunque creo que tampoco funciona en safari).

Aquí están las 2 directivas, ngDrop y input.

angular.module('myApp').directive("ngDrop", function($rootScope) {
    var link = function($scope, elements, attr, ngModel) {

        var parseInput = function(event) {
            var list = [];
            $scope.count = 0;

            var toParse = [];
            for (var i = 0; i < event.dataTransfer.items.length; i++) {
                toParse.push(event.dataTransfer.items[i].webkitGetAsEntry());
            }

            var traverse_directory = function(entry) {
                var reader = entry.createReader();
                // Resolved when the entire directory is traversed
                return new Promise(function executer(resolve_directory) {
                    var iteration_attempts = [];
                    (function read_entries() {
                        // According to the FileSystem API spec, readEntries() must be called until
                        // it calls the callback with an empty array.  Seriously??
                        reader.readEntries(function(entries) {
                            if (!entries.length) {
                                // Don,e iterating this particular directory
                                resolve_directory(Promise.all(iteration_attempts));
                            } else {
                                // Add a list of promises for each directory entry.  If the entry is itself
                                // a directory, then that promise won't resolve until it is fully traversed.
                                iteration_attempts.push(Promise.all(entries.map(function(entry) {
                                    if (entry.isFile) {
                                        list.push(entry);
                                        return entry;
                                    } else {
                                        return traverse_directory(entry);
                                    }
                                })));
                                // Try calling readEntries() again for the same dir, according to spec
                                read_entries();
                            }
                        });
                    })();
                });
            };

            var updateNgModel = function() {
                var files = [], count = 0;
                for (var i = 0; i < list.length; i++) {
                    list[i].file(function(file) {
                        files.push(file);
                        count++;
                        if (count === list.length) {
                            ngModel.$setViewValue(files);
                        }
                    });
                }
            };

            for (var j = 0; j < toParse.length; j++) {
                if (toParse[j].isFile) {
                    list.push(toParse[j]);
                } else if (toParse[j].isDirectory) {
                    $scope.count++;
                    traverse_directory(toParse[j]).then(function() {
                        $scope.count--;
                        if ($scope.count == 0) {
                            updateNgModel();
                        }
                    });
                }
            }
            if ($scope.count == 0) {
                updateNgModel();
            }
        }

        elements[0].ondrop = function(event) {
            event.stopPropagation();
            event.preventDefault();

            // ... styling

            parseInput(event);
        };

        elements[0].ondragover = function(event) {
            event.preventDefault();
        };
    };

    return {
        restrict: 'A',
        require:"^ngModel",
        link: link
    };
});

// select file on input
angular.module('myApp').directive("input", function($rootScope) {
    var link = function($scope, elements, attr, ngModel) {
        if (attr.type && attr.type.toLowerCase() === 'file') {
            elements[0].onchange = function(event) {
                var list = event.__files_ || (event.target && event.target.files);
                var files = [];
                for (var i = 0; i < list.length; i++) {
                    files.push(list[i]);
                }
                ngModel.$setViewValue(files);
            };
        }
    };

    return {
        restrict: 'E',
        require:"^ngModel",
        link: link
    };
});

Sobre la implementación, así es como los uso:

<div class="dropzone" ng-model="files" ng-drop>
    <input type="file" ng-model="files" webkitdirectory multiple>
    <h2><i class="fa fa-upload"></i> Drop Images Here !</h2>
    <div>Or just click to select files.</div>
</div>

Ambas directivas se utilizan principalmente para llenar el ngModel.

Aquí hay un plunkr

Ahora cuando arrastro / suelto en FF:TypeError: event.dataTransfer.items is undefined y cuando selecciono:TypeError: list is null

¿Qué puedo cambiar para que funcione tanto en Chrome como en Firefox, y por qué no, también en otros navegadores al mismo tiempo?

Respuestas a la pregunta(2)

Su respuesta a la pregunta