@@ 2271-2615 (lines=345) @@ | ||
2268 | return upload; |
|
2269 | }]); |
|
2270 | ||
2271 | (function () { |
|
2272 | ngFileUpload.directive('ngfDrop', ['$parse', '$timeout', '$window', 'Upload', '$http', '$q', |
|
2273 | function ($parse, $timeout, $window, Upload, $http, $q) { |
|
2274 | return { |
|
2275 | restrict: 'AEC', |
|
2276 | require: '?ngModel', |
|
2277 | link: function (scope, elem, attr, ngModel) { |
|
2278 | linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $window, Upload, $http, $q); |
|
2279 | } |
|
2280 | }; |
|
2281 | }]); |
|
2282 | ||
2283 | ngFileUpload.directive('ngfNoFileDrop', function () { |
|
2284 | return function (scope, elem) { |
|
2285 | if (dropAvailable()) elem.css('display', 'none'); |
|
2286 | }; |
|
2287 | }); |
|
2288 | ||
2289 | ngFileUpload.directive('ngfDropAvailable', ['$parse', '$timeout', 'Upload', function ($parse, $timeout, Upload) { |
|
2290 | return function (scope, elem, attr) { |
|
2291 | if (dropAvailable()) { |
|
2292 | var model = $parse(Upload.attrGetter('ngfDropAvailable', attr)); |
|
2293 | $timeout(function () { |
|
2294 | model(scope); |
|
2295 | if (model.assign) { |
|
2296 | model.assign(scope, true); |
|
2297 | } |
|
2298 | }); |
|
2299 | } |
|
2300 | }; |
|
2301 | }]); |
|
2302 | ||
2303 | function linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $window, upload, $http, $q) { |
|
2304 | var available = dropAvailable(); |
|
2305 | ||
2306 | var attrGetter = function (name, scope, params) { |
|
2307 | return upload.attrGetter(name, attr, scope, params); |
|
2308 | }; |
|
2309 | ||
2310 | if (attrGetter('dropAvailable')) { |
|
2311 | $timeout(function () { |
|
2312 | if (scope[attrGetter('dropAvailable')]) { |
|
2313 | scope[attrGetter('dropAvailable')].value = available; |
|
2314 | } else { |
|
2315 | scope[attrGetter('dropAvailable')] = available; |
|
2316 | } |
|
2317 | }); |
|
2318 | } |
|
2319 | if (!available) { |
|
2320 | if (attrGetter('ngfHideOnDropNotAvailable', scope) === true) { |
|
2321 | elem.css('display', 'none'); |
|
2322 | } |
|
2323 | return; |
|
2324 | } |
|
2325 | ||
2326 | function isDisabled() { |
|
2327 | return elem.attr('disabled') || attrGetter('ngfDropDisabled', scope); |
|
2328 | } |
|
2329 | ||
2330 | if (attrGetter('ngfSelect') == null) { |
|
2331 | upload.registerModelChangeValidator(ngModel, attr, scope); |
|
2332 | } |
|
2333 | ||
2334 | var leaveTimeout = null; |
|
2335 | var stopPropagation = $parse(attrGetter('ngfStopPropagation')); |
|
2336 | var dragOverDelay = 1; |
|
2337 | var actualDragOverClass; |
|
2338 | ||
2339 | elem[0].addEventListener('dragover', function (evt) { |
|
2340 | if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return; |
|
2341 | evt.preventDefault(); |
|
2342 | if (stopPropagation(scope)) evt.stopPropagation(); |
|
2343 | // handling dragover events from the Chrome download bar |
|
2344 | if (navigator.userAgent.indexOf('Chrome') > -1) { |
|
2345 | var b = evt.dataTransfer.effectAllowed; |
|
2346 | evt.dataTransfer.dropEffect = ('move' === b || 'linkMove' === b) ? 'move' : 'copy'; |
|
2347 | } |
|
2348 | $timeout.cancel(leaveTimeout); |
|
2349 | if (!actualDragOverClass) { |
|
2350 | actualDragOverClass = 'C'; |
|
2351 | calculateDragOverClass(scope, attr, evt, function (clazz) { |
|
2352 | actualDragOverClass = clazz; |
|
2353 | elem.addClass(actualDragOverClass); |
|
2354 | attrGetter('ngfDrag', scope, {$isDragging: true, $class: actualDragOverClass, $event: evt}); |
|
2355 | }); |
|
2356 | } |
|
2357 | }, false); |
|
2358 | elem[0].addEventListener('dragenter', function (evt) { |
|
2359 | if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return; |
|
2360 | evt.preventDefault(); |
|
2361 | if (stopPropagation(scope)) evt.stopPropagation(); |
|
2362 | }, false); |
|
2363 | elem[0].addEventListener('dragleave', function (evt) { |
|
2364 | if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return; |
|
2365 | evt.preventDefault(); |
|
2366 | if (stopPropagation(scope)) evt.stopPropagation(); |
|
2367 | leaveTimeout = $timeout(function () { |
|
2368 | if (actualDragOverClass) elem.removeClass(actualDragOverClass); |
|
2369 | actualDragOverClass = null; |
|
2370 | attrGetter('ngfDrag', scope, {$isDragging: false, $event: evt}); |
|
2371 | }, dragOverDelay || 100); |
|
2372 | }, false); |
|
2373 | elem[0].addEventListener('drop', function (evt) { |
|
2374 | if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return; |
|
2375 | evt.preventDefault(); |
|
2376 | if (stopPropagation(scope)) evt.stopPropagation(); |
|
2377 | if (actualDragOverClass) elem.removeClass(actualDragOverClass); |
|
2378 | actualDragOverClass = null; |
|
2379 | var items = evt.dataTransfer.items; |
|
2380 | var html; |
|
2381 | try { |
|
2382 | html = evt.dataTransfer && evt.dataTransfer.getData && evt.dataTransfer.getData('text/html'); |
|
2383 | } catch (e) {/* Fix IE11 that throw error calling getData */ |
|
2384 | } |
|
2385 | ||
2386 | extractFiles(items, evt.dataTransfer.files, attrGetter('ngfAllowDir', scope) !== false, |
|
2387 | attrGetter('multiple') || attrGetter('ngfMultiple', scope)).then(function (files) { |
|
2388 | if (files.length) { |
|
2389 | updateModel(files, evt); |
|
2390 | } else { |
|
2391 | extractFilesFromHtml('dropUrl', html).then(function (files) { |
|
2392 | updateModel(files, evt); |
|
2393 | }); |
|
2394 | } |
|
2395 | }); |
|
2396 | }, false); |
|
2397 | elem[0].addEventListener('paste', function (evt) { |
|
2398 | if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && |
|
2399 | attrGetter('ngfEnableFirefoxPaste', scope)) { |
|
2400 | evt.preventDefault(); |
|
2401 | } |
|
2402 | if (isDisabled() || !upload.shouldUpdateOn('paste', attr, scope)) return; |
|
2403 | var files = []; |
|
2404 | var clipboard = evt.clipboardData || evt.originalEvent.clipboardData; |
|
2405 | if (clipboard && clipboard.items) { |
|
2406 | for (var k = 0; k < clipboard.items.length; k++) { |
|
2407 | if (clipboard.items[k].type.indexOf('image') !== -1) { |
|
2408 | files.push(clipboard.items[k].getAsFile()); |
|
2409 | } |
|
2410 | } |
|
2411 | } |
|
2412 | if (files.length) { |
|
2413 | updateModel(files, evt); |
|
2414 | } else { |
|
2415 | extractFilesFromHtml('pasteUrl', clipboard).then(function (files) { |
|
2416 | updateModel(files, evt); |
|
2417 | }); |
|
2418 | } |
|
2419 | }, false); |
|
2420 | ||
2421 | if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && |
|
2422 | attrGetter('ngfEnableFirefoxPaste', scope)) { |
|
2423 | elem.attr('contenteditable', true); |
|
2424 | elem.on('keypress', function (e) { |
|
2425 | if (!e.metaKey && !e.ctrlKey) { |
|
2426 | e.preventDefault(); |
|
2427 | } |
|
2428 | }); |
|
2429 | } |
|
2430 | ||
2431 | function updateModel(files, evt) { |
|
2432 | upload.updateModel(ngModel, attr, scope, attrGetter('ngfChange') || attrGetter('ngfDrop'), files, evt); |
|
2433 | } |
|
2434 | ||
2435 | function extractFilesFromHtml(updateOn, html) { |
|
2436 | if (!upload.shouldUpdateOn(updateOn, attr, scope) || typeof html !== 'string') return upload.rejectPromise([]); |
|
2437 | var urls = []; |
|
2438 | html.replace(/<(img src|img [^>]* src) *=\"([^\"]*)\"/gi, function (m, n, src) { |
|
2439 | urls.push(src); |
|
2440 | }); |
|
2441 | var promises = [], files = []; |
|
2442 | if (urls.length) { |
|
2443 | angular.forEach(urls, function (url) { |
|
2444 | promises.push(upload.urlToBlob(url).then(function (blob) { |
|
2445 | files.push(blob); |
|
2446 | })); |
|
2447 | }); |
|
2448 | var defer = $q.defer(); |
|
2449 | $q.all(promises).then(function () { |
|
2450 | defer.resolve(files); |
|
2451 | }, function (e) { |
|
2452 | defer.reject(e); |
|
2453 | }); |
|
2454 | return defer.promise; |
|
2455 | } |
|
2456 | return upload.emptyPromise(); |
|
2457 | } |
|
2458 | ||
2459 | function calculateDragOverClass(scope, attr, evt, callback) { |
|
2460 | var obj = attrGetter('ngfDragOverClass', scope, {$event: evt}), dClass = 'dragover'; |
|
2461 | if (angular.isString(obj)) { |
|
2462 | dClass = obj; |
|
2463 | } else if (obj) { |
|
2464 | if (obj.delay) dragOverDelay = obj.delay; |
|
2465 | if (obj.accept || obj.reject) { |
|
2466 | var items = evt.dataTransfer.items; |
|
2467 | if (items == null || !items.length) { |
|
2468 | dClass = obj.accept; |
|
2469 | } else { |
|
2470 | var pattern = obj.pattern || attrGetter('ngfPattern', scope, {$event: evt}); |
|
2471 | var len = items.length; |
|
2472 | while (len--) { |
|
2473 | if (!upload.validatePattern(items[len], pattern)) { |
|
2474 | dClass = obj.reject; |
|
2475 | break; |
|
2476 | } else { |
|
2477 | dClass = obj.accept; |
|
2478 | } |
|
2479 | } |
|
2480 | } |
|
2481 | } |
|
2482 | } |
|
2483 | callback(dClass); |
|
2484 | } |
|
2485 | ||
2486 | function extractFiles(items, fileList, allowDir, multiple) { |
|
2487 | var maxFiles = upload.getValidationAttr(attr, scope, 'maxFiles'); |
|
2488 | if (maxFiles == null) { |
|
2489 | maxFiles = Number.MAX_VALUE; |
|
2490 | } |
|
2491 | var maxTotalSize = upload.getValidationAttr(attr, scope, 'maxTotalSize'); |
|
2492 | if (maxTotalSize == null) { |
|
2493 | maxTotalSize = Number.MAX_VALUE; |
|
2494 | } |
|
2495 | var includeDir = attrGetter('ngfIncludeDir', scope); |
|
2496 | var files = [], totalSize = 0; |
|
2497 | ||
2498 | function traverseFileTree(entry, path) { |
|
2499 | var defer = $q.defer(); |
|
2500 | if (entry != null) { |
|
2501 | if (entry.isDirectory) { |
|
2502 | var promises = [upload.emptyPromise()]; |
|
2503 | if (includeDir) { |
|
2504 | var file = {type: 'directory'}; |
|
2505 | file.name = file.path = (path || '') + entry.name; |
|
2506 | files.push(file); |
|
2507 | } |
|
2508 | var dirReader = entry.createReader(); |
|
2509 | var entries = []; |
|
2510 | var readEntries = function () { |
|
2511 | dirReader.readEntries(function (results) { |
|
2512 | try { |
|
2513 | if (!results.length) { |
|
2514 | angular.forEach(entries.slice(0), function (e) { |
|
2515 | if (files.length <= maxFiles && totalSize <= maxTotalSize) { |
|
2516 | promises.push(traverseFileTree(e, (path ? path : '') + entry.name + '/')); |
|
2517 | } |
|
2518 | }); |
|
2519 | $q.all(promises).then(function () { |
|
2520 | defer.resolve(); |
|
2521 | }, function (e) { |
|
2522 | defer.reject(e); |
|
2523 | }); |
|
2524 | } else { |
|
2525 | entries = entries.concat(Array.prototype.slice.call(results || [], 0)); |
|
2526 | readEntries(); |
|
2527 | } |
|
2528 | } catch (e) { |
|
2529 | defer.reject(e); |
|
2530 | } |
|
2531 | }, function (e) { |
|
2532 | defer.reject(e); |
|
2533 | }); |
|
2534 | }; |
|
2535 | readEntries(); |
|
2536 | } else { |
|
2537 | entry.file(function (file) { |
|
2538 | try { |
|
2539 | file.path = (path ? path : '') + file.name; |
|
2540 | if (includeDir) { |
|
2541 | file = upload.rename(file, file.path); |
|
2542 | } |
|
2543 | files.push(file); |
|
2544 | totalSize += file.size; |
|
2545 | defer.resolve(); |
|
2546 | } catch (e) { |
|
2547 | defer.reject(e); |
|
2548 | } |
|
2549 | }, function (e) { |
|
2550 | defer.reject(e); |
|
2551 | }); |
|
2552 | } |
|
2553 | } |
|
2554 | return defer.promise; |
|
2555 | } |
|
2556 | ||
2557 | var promises = [upload.emptyPromise()]; |
|
2558 | ||
2559 | if (items && items.length > 0 && $window.location.protocol !== 'file:') { |
|
2560 | for (var i = 0; i < items.length; i++) { |
|
2561 | if (items[i].webkitGetAsEntry && items[i].webkitGetAsEntry() && items[i].webkitGetAsEntry().isDirectory) { |
|
2562 | var entry = items[i].webkitGetAsEntry(); |
|
2563 | if (entry.isDirectory && !allowDir) { |
|
2564 | continue; |
|
2565 | } |
|
2566 | if (entry != null) { |
|
2567 | promises.push(traverseFileTree(entry)); |
|
2568 | } |
|
2569 | } else { |
|
2570 | var f = items[i].getAsFile(); |
|
2571 | if (f != null) { |
|
2572 | files.push(f); |
|
2573 | totalSize += f.size; |
|
2574 | } |
|
2575 | } |
|
2576 | if (files.length > maxFiles || totalSize > maxTotalSize || |
|
2577 | (!multiple && files.length > 0)) break; |
|
2578 | } |
|
2579 | } else { |
|
2580 | if (fileList != null) { |
|
2581 | for (var j = 0; j < fileList.length; j++) { |
|
2582 | var file = fileList.item(j); |
|
2583 | if (file.type || file.size > 0) { |
|
2584 | files.push(file); |
|
2585 | totalSize += file.size; |
|
2586 | } |
|
2587 | if (files.length > maxFiles || totalSize > maxTotalSize || |
|
2588 | (!multiple && files.length > 0)) break; |
|
2589 | } |
|
2590 | } |
|
2591 | } |
|
2592 | ||
2593 | var defer = $q.defer(); |
|
2594 | $q.all(promises).then(function () { |
|
2595 | if (!multiple && !includeDir && files.length) { |
|
2596 | var i = 0; |
|
2597 | while (files[i] && files[i].type === 'directory') i++; |
|
2598 | defer.resolve([files[i]]); |
|
2599 | } else { |
|
2600 | defer.resolve(files); |
|
2601 | } |
|
2602 | }, function (e) { |
|
2603 | defer.reject(e); |
|
2604 | }); |
|
2605 | ||
2606 | return defer.promise; |
|
2607 | } |
|
2608 | } |
|
2609 | ||
2610 | function dropAvailable() { |
|
2611 | var div = document.createElement('div'); |
|
2612 | return ('draggable' in div) && ('ondrop' in div) && !/Edge\/12./i.test(navigator.userAgent); |
|
2613 | } |
|
2614 | ||
2615 | })(); |
|
2616 | ||
2617 | // customized version of https://github.com/exif-js/exif-js |
|
2618 | ngFileUpload.service('UploadExif', ['UploadResize', '$q', function (UploadResize, $q) { |
@@ 1849-2193 (lines=345) @@ | ||
1846 | return upload; |
|
1847 | }]); |
|
1848 | ||
1849 | (function () { |
|
1850 | ngFileUpload.directive('ngfDrop', ['$parse', '$timeout', '$window', 'Upload', '$http', '$q', |
|
1851 | function ($parse, $timeout, $window, Upload, $http, $q) { |
|
1852 | return { |
|
1853 | restrict: 'AEC', |
|
1854 | require: '?ngModel', |
|
1855 | link: function (scope, elem, attr, ngModel) { |
|
1856 | linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $window, Upload, $http, $q); |
|
1857 | } |
|
1858 | }; |
|
1859 | }]); |
|
1860 | ||
1861 | ngFileUpload.directive('ngfNoFileDrop', function () { |
|
1862 | return function (scope, elem) { |
|
1863 | if (dropAvailable()) elem.css('display', 'none'); |
|
1864 | }; |
|
1865 | }); |
|
1866 | ||
1867 | ngFileUpload.directive('ngfDropAvailable', ['$parse', '$timeout', 'Upload', function ($parse, $timeout, Upload) { |
|
1868 | return function (scope, elem, attr) { |
|
1869 | if (dropAvailable()) { |
|
1870 | var model = $parse(Upload.attrGetter('ngfDropAvailable', attr)); |
|
1871 | $timeout(function () { |
|
1872 | model(scope); |
|
1873 | if (model.assign) { |
|
1874 | model.assign(scope, true); |
|
1875 | } |
|
1876 | }); |
|
1877 | } |
|
1878 | }; |
|
1879 | }]); |
|
1880 | ||
1881 | function linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $window, upload, $http, $q) { |
|
1882 | var available = dropAvailable(); |
|
1883 | ||
1884 | var attrGetter = function (name, scope, params) { |
|
1885 | return upload.attrGetter(name, attr, scope, params); |
|
1886 | }; |
|
1887 | ||
1888 | if (attrGetter('dropAvailable')) { |
|
1889 | $timeout(function () { |
|
1890 | if (scope[attrGetter('dropAvailable')]) { |
|
1891 | scope[attrGetter('dropAvailable')].value = available; |
|
1892 | } else { |
|
1893 | scope[attrGetter('dropAvailable')] = available; |
|
1894 | } |
|
1895 | }); |
|
1896 | } |
|
1897 | if (!available) { |
|
1898 | if (attrGetter('ngfHideOnDropNotAvailable', scope) === true) { |
|
1899 | elem.css('display', 'none'); |
|
1900 | } |
|
1901 | return; |
|
1902 | } |
|
1903 | ||
1904 | function isDisabled() { |
|
1905 | return elem.attr('disabled') || attrGetter('ngfDropDisabled', scope); |
|
1906 | } |
|
1907 | ||
1908 | if (attrGetter('ngfSelect') == null) { |
|
1909 | upload.registerModelChangeValidator(ngModel, attr, scope); |
|
1910 | } |
|
1911 | ||
1912 | var leaveTimeout = null; |
|
1913 | var stopPropagation = $parse(attrGetter('ngfStopPropagation')); |
|
1914 | var dragOverDelay = 1; |
|
1915 | var actualDragOverClass; |
|
1916 | ||
1917 | elem[0].addEventListener('dragover', function (evt) { |
|
1918 | if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return; |
|
1919 | evt.preventDefault(); |
|
1920 | if (stopPropagation(scope)) evt.stopPropagation(); |
|
1921 | // handling dragover events from the Chrome download bar |
|
1922 | if (navigator.userAgent.indexOf('Chrome') > -1) { |
|
1923 | var b = evt.dataTransfer.effectAllowed; |
|
1924 | evt.dataTransfer.dropEffect = ('move' === b || 'linkMove' === b) ? 'move' : 'copy'; |
|
1925 | } |
|
1926 | $timeout.cancel(leaveTimeout); |
|
1927 | if (!actualDragOverClass) { |
|
1928 | actualDragOverClass = 'C'; |
|
1929 | calculateDragOverClass(scope, attr, evt, function (clazz) { |
|
1930 | actualDragOverClass = clazz; |
|
1931 | elem.addClass(actualDragOverClass); |
|
1932 | attrGetter('ngfDrag', scope, {$isDragging: true, $class: actualDragOverClass, $event: evt}); |
|
1933 | }); |
|
1934 | } |
|
1935 | }, false); |
|
1936 | elem[0].addEventListener('dragenter', function (evt) { |
|
1937 | if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return; |
|
1938 | evt.preventDefault(); |
|
1939 | if (stopPropagation(scope)) evt.stopPropagation(); |
|
1940 | }, false); |
|
1941 | elem[0].addEventListener('dragleave', function (evt) { |
|
1942 | if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return; |
|
1943 | evt.preventDefault(); |
|
1944 | if (stopPropagation(scope)) evt.stopPropagation(); |
|
1945 | leaveTimeout = $timeout(function () { |
|
1946 | if (actualDragOverClass) elem.removeClass(actualDragOverClass); |
|
1947 | actualDragOverClass = null; |
|
1948 | attrGetter('ngfDrag', scope, {$isDragging: false, $event: evt}); |
|
1949 | }, dragOverDelay || 100); |
|
1950 | }, false); |
|
1951 | elem[0].addEventListener('drop', function (evt) { |
|
1952 | if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return; |
|
1953 | evt.preventDefault(); |
|
1954 | if (stopPropagation(scope)) evt.stopPropagation(); |
|
1955 | if (actualDragOverClass) elem.removeClass(actualDragOverClass); |
|
1956 | actualDragOverClass = null; |
|
1957 | var items = evt.dataTransfer.items; |
|
1958 | var html; |
|
1959 | try { |
|
1960 | html = evt.dataTransfer && evt.dataTransfer.getData && evt.dataTransfer.getData('text/html'); |
|
1961 | } catch (e) {/* Fix IE11 that throw error calling getData */ |
|
1962 | } |
|
1963 | ||
1964 | extractFiles(items, evt.dataTransfer.files, attrGetter('ngfAllowDir', scope) !== false, |
|
1965 | attrGetter('multiple') || attrGetter('ngfMultiple', scope)).then(function (files) { |
|
1966 | if (files.length) { |
|
1967 | updateModel(files, evt); |
|
1968 | } else { |
|
1969 | extractFilesFromHtml('dropUrl', html).then(function (files) { |
|
1970 | updateModel(files, evt); |
|
1971 | }); |
|
1972 | } |
|
1973 | }); |
|
1974 | }, false); |
|
1975 | elem[0].addEventListener('paste', function (evt) { |
|
1976 | if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && |
|
1977 | attrGetter('ngfEnableFirefoxPaste', scope)) { |
|
1978 | evt.preventDefault(); |
|
1979 | } |
|
1980 | if (isDisabled() || !upload.shouldUpdateOn('paste', attr, scope)) return; |
|
1981 | var files = []; |
|
1982 | var clipboard = evt.clipboardData || evt.originalEvent.clipboardData; |
|
1983 | if (clipboard && clipboard.items) { |
|
1984 | for (var k = 0; k < clipboard.items.length; k++) { |
|
1985 | if (clipboard.items[k].type.indexOf('image') !== -1) { |
|
1986 | files.push(clipboard.items[k].getAsFile()); |
|
1987 | } |
|
1988 | } |
|
1989 | } |
|
1990 | if (files.length) { |
|
1991 | updateModel(files, evt); |
|
1992 | } else { |
|
1993 | extractFilesFromHtml('pasteUrl', clipboard).then(function (files) { |
|
1994 | updateModel(files, evt); |
|
1995 | }); |
|
1996 | } |
|
1997 | }, false); |
|
1998 | ||
1999 | if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && |
|
2000 | attrGetter('ngfEnableFirefoxPaste', scope)) { |
|
2001 | elem.attr('contenteditable', true); |
|
2002 | elem.on('keypress', function (e) { |
|
2003 | if (!e.metaKey && !e.ctrlKey) { |
|
2004 | e.preventDefault(); |
|
2005 | } |
|
2006 | }); |
|
2007 | } |
|
2008 | ||
2009 | function updateModel(files, evt) { |
|
2010 | upload.updateModel(ngModel, attr, scope, attrGetter('ngfChange') || attrGetter('ngfDrop'), files, evt); |
|
2011 | } |
|
2012 | ||
2013 | function extractFilesFromHtml(updateOn, html) { |
|
2014 | if (!upload.shouldUpdateOn(updateOn, attr, scope) || typeof html !== 'string') return upload.rejectPromise([]); |
|
2015 | var urls = []; |
|
2016 | html.replace(/<(img src|img [^>]* src) *=\"([^\"]*)\"/gi, function (m, n, src) { |
|
2017 | urls.push(src); |
|
2018 | }); |
|
2019 | var promises = [], files = []; |
|
2020 | if (urls.length) { |
|
2021 | angular.forEach(urls, function (url) { |
|
2022 | promises.push(upload.urlToBlob(url).then(function (blob) { |
|
2023 | files.push(blob); |
|
2024 | })); |
|
2025 | }); |
|
2026 | var defer = $q.defer(); |
|
2027 | $q.all(promises).then(function () { |
|
2028 | defer.resolve(files); |
|
2029 | }, function (e) { |
|
2030 | defer.reject(e); |
|
2031 | }); |
|
2032 | return defer.promise; |
|
2033 | } |
|
2034 | return upload.emptyPromise(); |
|
2035 | } |
|
2036 | ||
2037 | function calculateDragOverClass(scope, attr, evt, callback) { |
|
2038 | var obj = attrGetter('ngfDragOverClass', scope, {$event: evt}), dClass = 'dragover'; |
|
2039 | if (angular.isString(obj)) { |
|
2040 | dClass = obj; |
|
2041 | } else if (obj) { |
|
2042 | if (obj.delay) dragOverDelay = obj.delay; |
|
2043 | if (obj.accept || obj.reject) { |
|
2044 | var items = evt.dataTransfer.items; |
|
2045 | if (items == null || !items.length) { |
|
2046 | dClass = obj.accept; |
|
2047 | } else { |
|
2048 | var pattern = obj.pattern || attrGetter('ngfPattern', scope, {$event: evt}); |
|
2049 | var len = items.length; |
|
2050 | while (len--) { |
|
2051 | if (!upload.validatePattern(items[len], pattern)) { |
|
2052 | dClass = obj.reject; |
|
2053 | break; |
|
2054 | } else { |
|
2055 | dClass = obj.accept; |
|
2056 | } |
|
2057 | } |
|
2058 | } |
|
2059 | } |
|
2060 | } |
|
2061 | callback(dClass); |
|
2062 | } |
|
2063 | ||
2064 | function extractFiles(items, fileList, allowDir, multiple) { |
|
2065 | var maxFiles = upload.getValidationAttr(attr, scope, 'maxFiles'); |
|
2066 | if (maxFiles == null) { |
|
2067 | maxFiles = Number.MAX_VALUE; |
|
2068 | } |
|
2069 | var maxTotalSize = upload.getValidationAttr(attr, scope, 'maxTotalSize'); |
|
2070 | if (maxTotalSize == null) { |
|
2071 | maxTotalSize = Number.MAX_VALUE; |
|
2072 | } |
|
2073 | var includeDir = attrGetter('ngfIncludeDir', scope); |
|
2074 | var files = [], totalSize = 0; |
|
2075 | ||
2076 | function traverseFileTree(entry, path) { |
|
2077 | var defer = $q.defer(); |
|
2078 | if (entry != null) { |
|
2079 | if (entry.isDirectory) { |
|
2080 | var promises = [upload.emptyPromise()]; |
|
2081 | if (includeDir) { |
|
2082 | var file = {type: 'directory'}; |
|
2083 | file.name = file.path = (path || '') + entry.name; |
|
2084 | files.push(file); |
|
2085 | } |
|
2086 | var dirReader = entry.createReader(); |
|
2087 | var entries = []; |
|
2088 | var readEntries = function () { |
|
2089 | dirReader.readEntries(function (results) { |
|
2090 | try { |
|
2091 | if (!results.length) { |
|
2092 | angular.forEach(entries.slice(0), function (e) { |
|
2093 | if (files.length <= maxFiles && totalSize <= maxTotalSize) { |
|
2094 | promises.push(traverseFileTree(e, (path ? path : '') + entry.name + '/')); |
|
2095 | } |
|
2096 | }); |
|
2097 | $q.all(promises).then(function () { |
|
2098 | defer.resolve(); |
|
2099 | }, function (e) { |
|
2100 | defer.reject(e); |
|
2101 | }); |
|
2102 | } else { |
|
2103 | entries = entries.concat(Array.prototype.slice.call(results || [], 0)); |
|
2104 | readEntries(); |
|
2105 | } |
|
2106 | } catch (e) { |
|
2107 | defer.reject(e); |
|
2108 | } |
|
2109 | }, function (e) { |
|
2110 | defer.reject(e); |
|
2111 | }); |
|
2112 | }; |
|
2113 | readEntries(); |
|
2114 | } else { |
|
2115 | entry.file(function (file) { |
|
2116 | try { |
|
2117 | file.path = (path ? path : '') + file.name; |
|
2118 | if (includeDir) { |
|
2119 | file = upload.rename(file, file.path); |
|
2120 | } |
|
2121 | files.push(file); |
|
2122 | totalSize += file.size; |
|
2123 | defer.resolve(); |
|
2124 | } catch (e) { |
|
2125 | defer.reject(e); |
|
2126 | } |
|
2127 | }, function (e) { |
|
2128 | defer.reject(e); |
|
2129 | }); |
|
2130 | } |
|
2131 | } |
|
2132 | return defer.promise; |
|
2133 | } |
|
2134 | ||
2135 | var promises = [upload.emptyPromise()]; |
|
2136 | ||
2137 | if (items && items.length > 0 && $window.location.protocol !== 'file:') { |
|
2138 | for (var i = 0; i < items.length; i++) { |
|
2139 | if (items[i].webkitGetAsEntry && items[i].webkitGetAsEntry() && items[i].webkitGetAsEntry().isDirectory) { |
|
2140 | var entry = items[i].webkitGetAsEntry(); |
|
2141 | if (entry.isDirectory && !allowDir) { |
|
2142 | continue; |
|
2143 | } |
|
2144 | if (entry != null) { |
|
2145 | promises.push(traverseFileTree(entry)); |
|
2146 | } |
|
2147 | } else { |
|
2148 | var f = items[i].getAsFile(); |
|
2149 | if (f != null) { |
|
2150 | files.push(f); |
|
2151 | totalSize += f.size; |
|
2152 | } |
|
2153 | } |
|
2154 | if (files.length > maxFiles || totalSize > maxTotalSize || |
|
2155 | (!multiple && files.length > 0)) break; |
|
2156 | } |
|
2157 | } else { |
|
2158 | if (fileList != null) { |
|
2159 | for (var j = 0; j < fileList.length; j++) { |
|
2160 | var file = fileList.item(j); |
|
2161 | if (file.type || file.size > 0) { |
|
2162 | files.push(file); |
|
2163 | totalSize += file.size; |
|
2164 | } |
|
2165 | if (files.length > maxFiles || totalSize > maxTotalSize || |
|
2166 | (!multiple && files.length > 0)) break; |
|
2167 | } |
|
2168 | } |
|
2169 | } |
|
2170 | ||
2171 | var defer = $q.defer(); |
|
2172 | $q.all(promises).then(function () { |
|
2173 | if (!multiple && !includeDir && files.length) { |
|
2174 | var i = 0; |
|
2175 | while (files[i] && files[i].type === 'directory') i++; |
|
2176 | defer.resolve([files[i]]); |
|
2177 | } else { |
|
2178 | defer.resolve(files); |
|
2179 | } |
|
2180 | }, function (e) { |
|
2181 | defer.reject(e); |
|
2182 | }); |
|
2183 | ||
2184 | return defer.promise; |
|
2185 | } |
|
2186 | } |
|
2187 | ||
2188 | function dropAvailable() { |
|
2189 | var div = document.createElement('div'); |
|
2190 | return ('draggable' in div) && ('ondrop' in div) && !/Edge\/12./i.test(navigator.userAgent); |
|
2191 | } |
|
2192 | ||
2193 | })(); |
|
2194 | ||
2195 | // customized version of https://github.com/exif-js/exif-js |
|
2196 | ngFileUpload.service('UploadExif', ['UploadResize', '$q', function (UploadResize, $q) { |
@@ 1-345 (lines=345) @@ | ||
1 | (function () { |
|
2 | ngFileUpload.directive('ngfDrop', ['$parse', '$timeout', '$window', 'Upload', '$http', '$q', |
|
3 | function ($parse, $timeout, $window, Upload, $http, $q) { |
|
4 | return { |
|
5 | restrict: 'AEC', |
|
6 | require: '?ngModel', |
|
7 | link: function (scope, elem, attr, ngModel) { |
|
8 | linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $window, Upload, $http, $q); |
|
9 | } |
|
10 | }; |
|
11 | }]); |
|
12 | ||
13 | ngFileUpload.directive('ngfNoFileDrop', function () { |
|
14 | return function (scope, elem) { |
|
15 | if (dropAvailable()) elem.css('display', 'none'); |
|
16 | }; |
|
17 | }); |
|
18 | ||
19 | ngFileUpload.directive('ngfDropAvailable', ['$parse', '$timeout', 'Upload', function ($parse, $timeout, Upload) { |
|
20 | return function (scope, elem, attr) { |
|
21 | if (dropAvailable()) { |
|
22 | var model = $parse(Upload.attrGetter('ngfDropAvailable', attr)); |
|
23 | $timeout(function () { |
|
24 | model(scope); |
|
25 | if (model.assign) { |
|
26 | model.assign(scope, true); |
|
27 | } |
|
28 | }); |
|
29 | } |
|
30 | }; |
|
31 | }]); |
|
32 | ||
33 | function linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $window, upload, $http, $q) { |
|
34 | var available = dropAvailable(); |
|
35 | ||
36 | var attrGetter = function (name, scope, params) { |
|
37 | return upload.attrGetter(name, attr, scope, params); |
|
38 | }; |
|
39 | ||
40 | if (attrGetter('dropAvailable')) { |
|
41 | $timeout(function () { |
|
42 | if (scope[attrGetter('dropAvailable')]) { |
|
43 | scope[attrGetter('dropAvailable')].value = available; |
|
44 | } else { |
|
45 | scope[attrGetter('dropAvailable')] = available; |
|
46 | } |
|
47 | }); |
|
48 | } |
|
49 | if (!available) { |
|
50 | if (attrGetter('ngfHideOnDropNotAvailable', scope) === true) { |
|
51 | elem.css('display', 'none'); |
|
52 | } |
|
53 | return; |
|
54 | } |
|
55 | ||
56 | function isDisabled() { |
|
57 | return elem.attr('disabled') || attrGetter('ngfDropDisabled', scope); |
|
58 | } |
|
59 | ||
60 | if (attrGetter('ngfSelect') == null) { |
|
61 | upload.registerModelChangeValidator(ngModel, attr, scope); |
|
62 | } |
|
63 | ||
64 | var leaveTimeout = null; |
|
65 | var stopPropagation = $parse(attrGetter('ngfStopPropagation')); |
|
66 | var dragOverDelay = 1; |
|
67 | var actualDragOverClass; |
|
68 | ||
69 | elem[0].addEventListener('dragover', function (evt) { |
|
70 | if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return; |
|
71 | evt.preventDefault(); |
|
72 | if (stopPropagation(scope)) evt.stopPropagation(); |
|
73 | // handling dragover events from the Chrome download bar |
|
74 | if (navigator.userAgent.indexOf('Chrome') > -1) { |
|
75 | var b = evt.dataTransfer.effectAllowed; |
|
76 | evt.dataTransfer.dropEffect = ('move' === b || 'linkMove' === b) ? 'move' : 'copy'; |
|
77 | } |
|
78 | $timeout.cancel(leaveTimeout); |
|
79 | if (!actualDragOverClass) { |
|
80 | actualDragOverClass = 'C'; |
|
81 | calculateDragOverClass(scope, attr, evt, function (clazz) { |
|
82 | actualDragOverClass = clazz; |
|
83 | elem.addClass(actualDragOverClass); |
|
84 | attrGetter('ngfDrag', scope, {$isDragging: true, $class: actualDragOverClass, $event: evt}); |
|
85 | }); |
|
86 | } |
|
87 | }, false); |
|
88 | elem[0].addEventListener('dragenter', function (evt) { |
|
89 | if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return; |
|
90 | evt.preventDefault(); |
|
91 | if (stopPropagation(scope)) evt.stopPropagation(); |
|
92 | }, false); |
|
93 | elem[0].addEventListener('dragleave', function (evt) { |
|
94 | if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return; |
|
95 | evt.preventDefault(); |
|
96 | if (stopPropagation(scope)) evt.stopPropagation(); |
|
97 | leaveTimeout = $timeout(function () { |
|
98 | if (actualDragOverClass) elem.removeClass(actualDragOverClass); |
|
99 | actualDragOverClass = null; |
|
100 | attrGetter('ngfDrag', scope, {$isDragging: false, $event: evt}); |
|
101 | }, dragOverDelay || 100); |
|
102 | }, false); |
|
103 | elem[0].addEventListener('drop', function (evt) { |
|
104 | if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return; |
|
105 | evt.preventDefault(); |
|
106 | if (stopPropagation(scope)) evt.stopPropagation(); |
|
107 | if (actualDragOverClass) elem.removeClass(actualDragOverClass); |
|
108 | actualDragOverClass = null; |
|
109 | var items = evt.dataTransfer.items; |
|
110 | var html; |
|
111 | try { |
|
112 | html = evt.dataTransfer && evt.dataTransfer.getData && evt.dataTransfer.getData('text/html'); |
|
113 | } catch (e) {/* Fix IE11 that throw error calling getData */ |
|
114 | } |
|
115 | ||
116 | extractFiles(items, evt.dataTransfer.files, attrGetter('ngfAllowDir', scope) !== false, |
|
117 | attrGetter('multiple') || attrGetter('ngfMultiple', scope)).then(function (files) { |
|
118 | if (files.length) { |
|
119 | updateModel(files, evt); |
|
120 | } else { |
|
121 | extractFilesFromHtml('dropUrl', html).then(function (files) { |
|
122 | updateModel(files, evt); |
|
123 | }); |
|
124 | } |
|
125 | }); |
|
126 | }, false); |
|
127 | elem[0].addEventListener('paste', function (evt) { |
|
128 | if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && |
|
129 | attrGetter('ngfEnableFirefoxPaste', scope)) { |
|
130 | evt.preventDefault(); |
|
131 | } |
|
132 | if (isDisabled() || !upload.shouldUpdateOn('paste', attr, scope)) return; |
|
133 | var files = []; |
|
134 | var clipboard = evt.clipboardData || evt.originalEvent.clipboardData; |
|
135 | if (clipboard && clipboard.items) { |
|
136 | for (var k = 0; k < clipboard.items.length; k++) { |
|
137 | if (clipboard.items[k].type.indexOf('image') !== -1) { |
|
138 | files.push(clipboard.items[k].getAsFile()); |
|
139 | } |
|
140 | } |
|
141 | } |
|
142 | if (files.length) { |
|
143 | updateModel(files, evt); |
|
144 | } else { |
|
145 | extractFilesFromHtml('pasteUrl', clipboard).then(function (files) { |
|
146 | updateModel(files, evt); |
|
147 | }); |
|
148 | } |
|
149 | }, false); |
|
150 | ||
151 | if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && |
|
152 | attrGetter('ngfEnableFirefoxPaste', scope)) { |
|
153 | elem.attr('contenteditable', true); |
|
154 | elem.on('keypress', function (e) { |
|
155 | if (!e.metaKey && !e.ctrlKey) { |
|
156 | e.preventDefault(); |
|
157 | } |
|
158 | }); |
|
159 | } |
|
160 | ||
161 | function updateModel(files, evt) { |
|
162 | upload.updateModel(ngModel, attr, scope, attrGetter('ngfChange') || attrGetter('ngfDrop'), files, evt); |
|
163 | } |
|
164 | ||
165 | function extractFilesFromHtml(updateOn, html) { |
|
166 | if (!upload.shouldUpdateOn(updateOn, attr, scope) || typeof html !== 'string') return upload.rejectPromise([]); |
|
167 | var urls = []; |
|
168 | html.replace(/<(img src|img [^>]* src) *=\"([^\"]*)\"/gi, function (m, n, src) { |
|
169 | urls.push(src); |
|
170 | }); |
|
171 | var promises = [], files = []; |
|
172 | if (urls.length) { |
|
173 | angular.forEach(urls, function (url) { |
|
174 | promises.push(upload.urlToBlob(url).then(function (blob) { |
|
175 | files.push(blob); |
|
176 | })); |
|
177 | }); |
|
178 | var defer = $q.defer(); |
|
179 | $q.all(promises).then(function () { |
|
180 | defer.resolve(files); |
|
181 | }, function (e) { |
|
182 | defer.reject(e); |
|
183 | }); |
|
184 | return defer.promise; |
|
185 | } |
|
186 | return upload.emptyPromise(); |
|
187 | } |
|
188 | ||
189 | function calculateDragOverClass(scope, attr, evt, callback) { |
|
190 | var obj = attrGetter('ngfDragOverClass', scope, {$event: evt}), dClass = 'dragover'; |
|
191 | if (angular.isString(obj)) { |
|
192 | dClass = obj; |
|
193 | } else if (obj) { |
|
194 | if (obj.delay) dragOverDelay = obj.delay; |
|
195 | if (obj.accept || obj.reject) { |
|
196 | var items = evt.dataTransfer.items; |
|
197 | if (items == null || !items.length) { |
|
198 | dClass = obj.accept; |
|
199 | } else { |
|
200 | var pattern = obj.pattern || attrGetter('ngfPattern', scope, {$event: evt}); |
|
201 | var len = items.length; |
|
202 | while (len--) { |
|
203 | if (!upload.validatePattern(items[len], pattern)) { |
|
204 | dClass = obj.reject; |
|
205 | break; |
|
206 | } else { |
|
207 | dClass = obj.accept; |
|
208 | } |
|
209 | } |
|
210 | } |
|
211 | } |
|
212 | } |
|
213 | callback(dClass); |
|
214 | } |
|
215 | ||
216 | function extractFiles(items, fileList, allowDir, multiple) { |
|
217 | var maxFiles = upload.getValidationAttr(attr, scope, 'maxFiles'); |
|
218 | if (maxFiles == null) { |
|
219 | maxFiles = Number.MAX_VALUE; |
|
220 | } |
|
221 | var maxTotalSize = upload.getValidationAttr(attr, scope, 'maxTotalSize'); |
|
222 | if (maxTotalSize == null) { |
|
223 | maxTotalSize = Number.MAX_VALUE; |
|
224 | } |
|
225 | var includeDir = attrGetter('ngfIncludeDir', scope); |
|
226 | var files = [], totalSize = 0; |
|
227 | ||
228 | function traverseFileTree(entry, path) { |
|
229 | var defer = $q.defer(); |
|
230 | if (entry != null) { |
|
231 | if (entry.isDirectory) { |
|
232 | var promises = [upload.emptyPromise()]; |
|
233 | if (includeDir) { |
|
234 | var file = {type: 'directory'}; |
|
235 | file.name = file.path = (path || '') + entry.name; |
|
236 | files.push(file); |
|
237 | } |
|
238 | var dirReader = entry.createReader(); |
|
239 | var entries = []; |
|
240 | var readEntries = function () { |
|
241 | dirReader.readEntries(function (results) { |
|
242 | try { |
|
243 | if (!results.length) { |
|
244 | angular.forEach(entries.slice(0), function (e) { |
|
245 | if (files.length <= maxFiles && totalSize <= maxTotalSize) { |
|
246 | promises.push(traverseFileTree(e, (path ? path : '') + entry.name + '/')); |
|
247 | } |
|
248 | }); |
|
249 | $q.all(promises).then(function () { |
|
250 | defer.resolve(); |
|
251 | }, function (e) { |
|
252 | defer.reject(e); |
|
253 | }); |
|
254 | } else { |
|
255 | entries = entries.concat(Array.prototype.slice.call(results || [], 0)); |
|
256 | readEntries(); |
|
257 | } |
|
258 | } catch (e) { |
|
259 | defer.reject(e); |
|
260 | } |
|
261 | }, function (e) { |
|
262 | defer.reject(e); |
|
263 | }); |
|
264 | }; |
|
265 | readEntries(); |
|
266 | } else { |
|
267 | entry.file(function (file) { |
|
268 | try { |
|
269 | file.path = (path ? path : '') + file.name; |
|
270 | if (includeDir) { |
|
271 | file = upload.rename(file, file.path); |
|
272 | } |
|
273 | files.push(file); |
|
274 | totalSize += file.size; |
|
275 | defer.resolve(); |
|
276 | } catch (e) { |
|
277 | defer.reject(e); |
|
278 | } |
|
279 | }, function (e) { |
|
280 | defer.reject(e); |
|
281 | }); |
|
282 | } |
|
283 | } |
|
284 | return defer.promise; |
|
285 | } |
|
286 | ||
287 | var promises = [upload.emptyPromise()]; |
|
288 | ||
289 | if (items && items.length > 0 && $window.location.protocol !== 'file:') { |
|
290 | for (var i = 0; i < items.length; i++) { |
|
291 | if (items[i].webkitGetAsEntry && items[i].webkitGetAsEntry() && items[i].webkitGetAsEntry().isDirectory) { |
|
292 | var entry = items[i].webkitGetAsEntry(); |
|
293 | if (entry.isDirectory && !allowDir) { |
|
294 | continue; |
|
295 | } |
|
296 | if (entry != null) { |
|
297 | promises.push(traverseFileTree(entry)); |
|
298 | } |
|
299 | } else { |
|
300 | var f = items[i].getAsFile(); |
|
301 | if (f != null) { |
|
302 | files.push(f); |
|
303 | totalSize += f.size; |
|
304 | } |
|
305 | } |
|
306 | if (files.length > maxFiles || totalSize > maxTotalSize || |
|
307 | (!multiple && files.length > 0)) break; |
|
308 | } |
|
309 | } else { |
|
310 | if (fileList != null) { |
|
311 | for (var j = 0; j < fileList.length; j++) { |
|
312 | var file = fileList.item(j); |
|
313 | if (file.type || file.size > 0) { |
|
314 | files.push(file); |
|
315 | totalSize += file.size; |
|
316 | } |
|
317 | if (files.length > maxFiles || totalSize > maxTotalSize || |
|
318 | (!multiple && files.length > 0)) break; |
|
319 | } |
|
320 | } |
|
321 | } |
|
322 | ||
323 | var defer = $q.defer(); |
|
324 | $q.all(promises).then(function () { |
|
325 | if (!multiple && !includeDir && files.length) { |
|
326 | var i = 0; |
|
327 | while (files[i] && files[i].type === 'directory') i++; |
|
328 | defer.resolve([files[i]]); |
|
329 | } else { |
|
330 | defer.resolve(files); |
|
331 | } |
|
332 | }, function (e) { |
|
333 | defer.reject(e); |
|
334 | }); |
|
335 | ||
336 | return defer.promise; |
|
337 | } |
|
338 | } |
|
339 | ||
340 | function dropAvailable() { |
|
341 | var div = document.createElement('div'); |
|
342 | return ('draggable' in div) && ('ondrop' in div) && !/Edge\/12./i.test(navigator.userAgent); |
|
343 | } |
|
344 | ||
345 | })(); |
|
346 |