农燊高科官方网站
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

hace 4 años
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. /**
  2. * AJAX Upload ( http://valums.com/ajax-upload/ )
  3. * Copyright (c) Andrew Valums
  4. * Licensed under the MIT license
  5. */
  6. (function () {
  7. /**
  8. * Attaches event to a dom element.
  9. * @param {Element} el
  10. * @param type event name
  11. * @param fn callback This refers to the passed element
  12. */
  13. function addEvent(el, type, fn){
  14. if (el.addEventListener) {
  15. el.addEventListener(type, fn, false);
  16. } else if (el.attachEvent) {
  17. el.attachEvent('on' + type, function(){
  18. fn.call(el);
  19. });
  20. } else {
  21. throw new Error('not supported or DOM not loaded');
  22. }
  23. }
  24. /**
  25. * Attaches resize event to a window, limiting
  26. * number of event fired. Fires only when encounteres
  27. * delay of 100 after series of events.
  28. *
  29. * Some browsers fire event multiple times when resizing
  30. * http://www.quirksmode.org/dom/events/resize.html
  31. *
  32. * @param fn callback This refers to the passed element
  33. */
  34. function addResizeEvent(fn){
  35. var timeout;
  36. addEvent(window, 'resize', function(){
  37. if (timeout){
  38. clearTimeout(timeout);
  39. }
  40. timeout = setTimeout(fn, 100);
  41. });
  42. }
  43. // Needs more testing, will be rewriten for next version
  44. // getOffset function copied from jQuery lib (http://jquery.com/)
  45. if (document.documentElement.getBoundingClientRect){
  46. // Get Offset using getBoundingClientRect
  47. // http://ejohn.org/blog/getboundingclientrect-is-awesome/
  48. var getOffset = function(el){
  49. var box = el.getBoundingClientRect();
  50. var doc = el.ownerDocument;
  51. var body = doc.body;
  52. var docElem = doc.documentElement; // for ie
  53. var clientTop = docElem.clientTop || body.clientTop || 0;
  54. var clientLeft = docElem.clientLeft || body.clientLeft || 0;
  55. // In Internet Explorer 7 getBoundingClientRect property is treated as physical,
  56. // while others are logical. Make all logical, like in IE8.
  57. var zoom = 1;
  58. if (body.getBoundingClientRect) {
  59. var bound = body.getBoundingClientRect();
  60. zoom = (bound.right - bound.left) / body.clientWidth;
  61. }
  62. if (zoom > 1) {
  63. clientTop = 0;
  64. clientLeft = 0;
  65. }
  66. var top = box.top / zoom + (window.pageYOffset || docElem && docElem.scrollTop / zoom || body.scrollTop / zoom) - clientTop, left = box.left / zoom + (window.pageXOffset || docElem && docElem.scrollLeft / zoom || body.scrollLeft / zoom) - clientLeft;
  67. return {
  68. top: top,
  69. left: left
  70. };
  71. };
  72. } else {
  73. // Get offset adding all offsets
  74. var getOffset = function(el){
  75. var top = 0, left = 0;
  76. do {
  77. top += el.offsetTop || 0;
  78. left += el.offsetLeft || 0;
  79. el = el.offsetParent;
  80. } while (el);
  81. return {
  82. left: left,
  83. top: top
  84. };
  85. };
  86. }
  87. /**
  88. * Returns left, top, right and bottom properties describing the border-box,
  89. * in pixels, with the top-left relative to the body
  90. * @param {Element} el
  91. * @return {Object} Contains left, top, right,bottom
  92. */
  93. function getBox(el){
  94. var left, right, top, bottom;
  95. var offset = getOffset(el);
  96. left = offset.left;
  97. top = offset.top;
  98. right = left + el.offsetWidth;
  99. bottom = top + el.offsetHeight;
  100. return {
  101. left: left,
  102. right: right,
  103. top: top,
  104. bottom: bottom
  105. };
  106. }
  107. /**
  108. * Helper that takes object literal
  109. * and add all properties to element.style
  110. * @param {Element} el
  111. * @param {Object} styles
  112. */
  113. function addStyles(el, styles){
  114. for (var name in styles) {
  115. if (styles.hasOwnProperty(name)) {
  116. el.style[name] = styles[name];
  117. }
  118. }
  119. }
  120. /**
  121. * Function places an absolutely positioned
  122. * element on top of the specified element
  123. * copying position and dimentions.
  124. * @param {Element} from
  125. * @param {Element} to
  126. */
  127. function copyLayout(from, to){
  128. var box = getBox(from);
  129. addStyles(to, {
  130. position: 'absolute',
  131. left : box.left + 'px',
  132. top : box.top + 'px',
  133. width : from.offsetWidth + 'px',
  134. height : from.offsetHeight + 'px'
  135. });
  136. }
  137. /**
  138. * Creates and returns element from html chunk
  139. * Uses innerHTML to create an element
  140. */
  141. var toElement = (function(){
  142. var div = document.createElement('div');
  143. return function(html){
  144. div.innerHTML = html;
  145. var el = div.firstChild;
  146. return div.removeChild(el);
  147. };
  148. })();
  149. /**
  150. * Function generates unique id
  151. * @return unique id
  152. */
  153. var getUID = (function(){
  154. var id = 0;
  155. return function(){
  156. return 'ValumsAjaxUpload' + id++;
  157. };
  158. })();
  159. /**
  160. * Get file name from path
  161. * @param {String} file path to file
  162. * @return filename
  163. */
  164. function fileFromPath(file){
  165. return file.replace(/.*(\/|\\)/, "");
  166. }
  167. /**
  168. * Get file extension lowercase
  169. * @param {String} file name
  170. * @return file extenstion
  171. */
  172. function getExt(file){
  173. return (-1 !== file.indexOf('.')) ? file.replace(/.*[.]/, '') : '';
  174. }
  175. function hasClass(el, name){
  176. var re = new RegExp('\\b' + name + '\\b');
  177. return re.test(el.className);
  178. }
  179. function addClass(el, name){
  180. if ( ! hasClass(el, name)){
  181. el.className += ' ' + name;
  182. }
  183. }
  184. function removeClass(el, name){
  185. var re = new RegExp('\\b' + name + '\\b');
  186. el.className = el.className.replace(re, '');
  187. }
  188. function removeNode(el){
  189. el.parentNode.removeChild(el);
  190. }
  191. /**
  192. * Easy styling and uploading
  193. * @constructor
  194. * @param button An element you want convert to
  195. * upload button. Tested dimentions up to 500x500px
  196. * @param {Object} options See defaults below.
  197. */
  198. window.AjaxUpload = function(button, options){
  199. this._settings = {
  200. // Location of the server-side upload script
  201. action: 'upload.php',
  202. // File upload name
  203. name: 'userfile',
  204. // Select & upload multiple files at once FF3.6+, Chrome 4+
  205. multiple: false,
  206. // Additional data to send
  207. data: {},
  208. // Submit file as soon as it's selected
  209. autoSubmit: true,
  210. // The type of data that you're expecting back from the server.
  211. // html and xml are detected automatically.
  212. // Only useful when you are using json data as a response.
  213. // Set to "json" in that case.
  214. responseType: false,
  215. // Class applied to button when mouse is hovered
  216. hoverClass: 'hover',
  217. // Class applied to button when button is focused
  218. focusClass: 'focus',
  219. // Class applied to button when AU is disabled
  220. disabledClass: 'disabled',
  221. // When user selects a file, useful with autoSubmit disabled
  222. // You can return false to cancel upload
  223. onChange: function(file, extension){
  224. },
  225. // Callback to fire before file is uploaded
  226. // You can return false to cancel upload
  227. onSubmit: function(file, extension){
  228. },
  229. // Fired when file upload is completed
  230. // WARNING! DO NOT USE "FALSE" STRING AS A RESPONSE!
  231. onComplete: function(file, response){
  232. }
  233. };
  234. // Merge the users options with our defaults
  235. for (var i in options) {
  236. if (options.hasOwnProperty(i)){
  237. this._settings[i] = options[i];
  238. }
  239. }
  240. // button isn't necessary a dom element
  241. if (button.jquery){
  242. // jQuery object was passed
  243. button = button[0];
  244. } else if (typeof button == "string") {
  245. if (/^#.*/.test(button)){
  246. // If jQuery user passes #elementId don't break it
  247. button = button.slice(1);
  248. }
  249. button = document.getElementById(button);
  250. }
  251. if ( ! button || button.nodeType !== 1){
  252. throw new Error("Please make sure that you're passing a valid element");
  253. }
  254. if ( button.nodeName.toUpperCase() == 'A'){
  255. // disable link
  256. addEvent(button, 'click', function(e){
  257. if (e && e.preventDefault){
  258. e.preventDefault();
  259. } else if (window.event){
  260. window.event.returnValue = false;
  261. }
  262. });
  263. }
  264. // DOM element
  265. this._button = button;
  266. // DOM element
  267. this._input = null;
  268. // If disabled clicking on button won't do anything
  269. this._disabled = false;
  270. // if the button was disabled before refresh if will remain
  271. // disabled in FireFox, let's fix it
  272. this.enable();
  273. this._rerouteClicks();
  274. };
  275. // assigning methods to our class
  276. AjaxUpload.prototype = {
  277. setData: function(data){
  278. this._settings.data = data;
  279. },
  280. disable: function(){
  281. addClass(this._button, this._settings.disabledClass);
  282. this._disabled = true;
  283. var nodeName = this._button.nodeName.toUpperCase();
  284. if (nodeName == 'INPUT' || nodeName == 'BUTTON'){
  285. this._button.setAttribute('disabled', 'disabled');
  286. }
  287. // hide input
  288. if (this._input){
  289. if (this._input.parentNode) {
  290. // We use visibility instead of display to fix problem with Safari 4
  291. // The problem is that the value of input doesn't change if it
  292. // has display none when user selects a file
  293. this._input.parentNode.style.visibility = 'hidden';
  294. }
  295. }
  296. },
  297. enable: function(){
  298. removeClass(this._button, this._settings.disabledClass);
  299. this._button.removeAttribute('disabled');
  300. this._disabled = false;
  301. },
  302. /**
  303. * Creates invisible file input
  304. * that will hover above the button
  305. * <div><input type='file' /></div>
  306. */
  307. _createInput: function(){
  308. var self = this;
  309. var input = document.createElement("input");
  310. input.setAttribute('type', 'file');
  311. input.setAttribute('name', this._settings.name);
  312. if(this._settings.multiple) input.setAttribute('multiple', 'multiple');
  313. addStyles(input, {
  314. 'position' : 'absolute',
  315. // in Opera only 'browse' button
  316. // is clickable and it is located at
  317. // the right side of the input
  318. 'right' : 0,
  319. 'margin' : 0,
  320. 'padding' : 0,
  321. 'fontSize' : '480px',
  322. // in Firefox if font-family is set to
  323. // 'inherit' the input doesn't work
  324. 'fontFamily' : 'sans-serif',
  325. 'cursor' : 'pointer'
  326. });
  327. var div = document.createElement("div");
  328. addStyles(div, {
  329. 'display' : 'block',
  330. 'position' : 'absolute',
  331. 'overflow' : 'hidden',
  332. 'margin' : 0,
  333. 'padding' : 0,
  334. 'opacity' : 0,
  335. // Make sure browse button is in the right side
  336. // in Internet Explorer
  337. 'direction' : 'ltr',
  338. //Max zIndex supported by Opera 9.0-9.2
  339. 'zIndex': 2147483583
  340. });
  341. // Make sure that element opacity exists.
  342. // Otherwise use IE filter
  343. if ( div.style.opacity !== "0") {
  344. if (typeof(div.filters) == 'undefined'){
  345. throw new Error('Opacity not supported by the browser');
  346. }
  347. div.style.filter = "alpha(opacity=0)";
  348. }
  349. addEvent(input, 'change', function(){
  350. if ( ! input || input.value === ''){
  351. return;
  352. }
  353. // Get filename from input, required
  354. // as some browsers have path instead of it
  355. var file = fileFromPath(input.value);
  356. if (false === self._settings.onChange.call(self, file, getExt(file))){
  357. self._clearInput();
  358. return;
  359. }
  360. // Submit form when value is changed
  361. if (self._settings.autoSubmit) {
  362. self.submit();
  363. }
  364. });
  365. addEvent(input, 'mouseover', function(){
  366. addClass(self._button, self._settings.hoverClass);
  367. });
  368. addEvent(input, 'mouseout', function(){
  369. removeClass(self._button, self._settings.hoverClass);
  370. removeClass(self._button, self._settings.focusClass);
  371. if (input.parentNode) {
  372. // We use visibility instead of display to fix problem with Safari 4
  373. // The problem is that the value of input doesn't change if it
  374. // has display none when user selects a file
  375. input.parentNode.style.visibility = 'hidden';
  376. }
  377. });
  378. addEvent(input, 'focus', function(){
  379. addClass(self._button, self._settings.focusClass);
  380. });
  381. addEvent(input, 'blur', function(){
  382. removeClass(self._button, self._settings.focusClass);
  383. });
  384. div.appendChild(input);
  385. document.body.appendChild(div);
  386. this._input = input;
  387. },
  388. _clearInput : function(){
  389. if (!this._input){
  390. return;
  391. }
  392. // this._input.value = ''; Doesn't work in IE6
  393. removeNode(this._input.parentNode);
  394. this._input = null;
  395. this._createInput();
  396. removeClass(this._button, this._settings.hoverClass);
  397. removeClass(this._button, this._settings.focusClass);
  398. },
  399. /**
  400. * Function makes sure that when user clicks upload button,
  401. * the this._input is clicked instead
  402. */
  403. _rerouteClicks: function(){
  404. var self = this;
  405. // IE will later display 'access denied' error
  406. // if you use using self._input.click()
  407. // other browsers just ignore click()
  408. addEvent(self._button, 'mouseover', function(){
  409. if (self._disabled){
  410. return;
  411. }
  412. if ( ! self._input){
  413. self._createInput();
  414. }
  415. var div = self._input.parentNode;
  416. copyLayout(self._button, div);
  417. div.style.visibility = 'visible';
  418. });
  419. // commented because we now hide input on mouseleave
  420. /**
  421. * When the window is resized the elements
  422. * can be misaligned if button position depends
  423. * on window size
  424. */
  425. //addResizeEvent(function(){
  426. // if (self._input){
  427. // copyLayout(self._button, self._input.parentNode);
  428. // }
  429. //});
  430. },
  431. /**
  432. * Creates iframe with unique name
  433. * @return {Element} iframe
  434. */
  435. _createIframe: function(){
  436. // We can't use getTime, because it sometimes return
  437. // same value in safari :(
  438. var id = getUID();
  439. // We can't use following code as the name attribute
  440. // won't be properly registered in IE6, and new window
  441. // on form submit will open
  442. // var iframe = document.createElement('iframe');
  443. // iframe.setAttribute('name', id);
  444. var iframe = toElement('<iframe src="javascript:false;" name="' + id + '" />');
  445. // src="javascript:false; was added
  446. // because it possibly removes ie6 prompt
  447. // "This page contains both secure and nonsecure items"
  448. // Anyway, it doesn't do any harm.
  449. iframe.setAttribute('id', id);
  450. iframe.style.display = 'none';
  451. document.body.appendChild(iframe);
  452. return iframe;
  453. },
  454. /**
  455. * Creates form, that will be submitted to iframe
  456. * @param {Element} iframe Where to submit
  457. * @return {Element} form
  458. */
  459. _createForm: function(iframe){
  460. var settings = this._settings;
  461. // We can't use the following code in IE6
  462. // var form = document.createElement('form');
  463. // form.setAttribute('method', 'post');
  464. // form.setAttribute('enctype', 'multipart/form-data');
  465. // Because in this case file won't be attached to request
  466. var form = toElement('<form method="post" enctype="multipart/form-data"></form>');
  467. form.setAttribute('action', settings.action);
  468. form.setAttribute('target', iframe.name);
  469. form.style.display = 'none';
  470. document.body.appendChild(form);
  471. // Create hidden input element for each data key
  472. for (var prop in settings.data) {
  473. if (settings.data.hasOwnProperty(prop)){
  474. var el = document.createElement("input");
  475. el.setAttribute('type', 'hidden');
  476. el.setAttribute('name', prop);
  477. el.setAttribute('value', settings.data[prop]);
  478. form.appendChild(el);
  479. }
  480. }
  481. return form;
  482. },
  483. /**
  484. * Gets response from iframe and fires onComplete event when ready
  485. * @param iframe
  486. * @param file Filename to use in onComplete callback
  487. */
  488. _getResponse : function(iframe, file){
  489. // getting response
  490. var toDeleteFlag = false, self = this, settings = this._settings;
  491. addEvent(iframe, 'load', function(){
  492. if (// For Safari
  493. iframe.src == "javascript:'%3Chtml%3E%3C/html%3E';" ||
  494. // For FF, IE
  495. iframe.src == "javascript:'<html></html>';"){
  496. // First time around, do not delete.
  497. // We reload to blank page, so that reloading main page
  498. // does not re-submit the post.
  499. if (toDeleteFlag) {
  500. // Fix busy state in FF3
  501. setTimeout(function(){
  502. removeNode(iframe);
  503. }, 0);
  504. }
  505. return;
  506. }
  507. var doc = iframe.contentDocument ? iframe.contentDocument : window.frames[iframe.id].document;
  508. // fixing Opera 9.26,10.00
  509. if (doc.readyState && doc.readyState != 'complete') {
  510. // Opera fires load event multiple times
  511. // Even when the DOM is not ready yet
  512. // this fix should not affect other browsers
  513. return;
  514. }
  515. // fixing Opera 9.64
  516. if (doc.body && doc.body.innerHTML == "false") {
  517. // In Opera 9.64 event was fired second time
  518. // when body.innerHTML changed from false
  519. // to server response approx. after 1 sec
  520. return;
  521. }
  522. var response;
  523. if (doc.XMLDocument) {
  524. // response is a xml document Internet Explorer property
  525. response = doc.XMLDocument;
  526. } else if (doc.body){
  527. // response is html document or plain text
  528. response = doc.body.innerHTML;
  529. if (settings.responseType && settings.responseType.toLowerCase() == 'json') {
  530. // If the document was sent as 'application/javascript' or
  531. // 'text/javascript', then the browser wraps the text in a <pre>
  532. // tag and performs html encoding on the contents. In this case,
  533. // we need to pull the original text content from the text node's
  534. // nodeValue property to retrieve the unmangled content.
  535. // Note that IE6 only understands text/html
  536. if (doc.body.firstChild && doc.body.firstChild.nodeName.toUpperCase() == 'PRE') {
  537. doc.normalize();
  538. response = doc.body.firstChild.firstChild.nodeValue;
  539. }
  540. if (response) {
  541. response = eval("(" + response + ")");
  542. } else {
  543. response = {};
  544. }
  545. }
  546. } else {
  547. // response is a xml document
  548. response = doc;
  549. }
  550. settings.onComplete.call(self, file, response);
  551. // Reload blank page, so that reloading main page
  552. // does not re-submit the post. Also, remember to
  553. // delete the frame
  554. toDeleteFlag = true;
  555. // Fix IE mixed content issue
  556. iframe.src = "javascript:'<html></html>';";
  557. });
  558. },
  559. /**
  560. * Upload file contained in this._input
  561. */
  562. submit: function(){
  563. var self = this, settings = this._settings;
  564. if ( ! this._input || this._input.value === ''){
  565. return;
  566. }
  567. var file = fileFromPath(this._input.value);
  568. // user returned false to cancel upload
  569. if (false === settings.onSubmit.call(this, file, getExt(file))){
  570. this._clearInput();
  571. return;
  572. }
  573. // sending request
  574. var iframe = this._createIframe();
  575. var form = this._createForm(iframe);
  576. // assuming following structure
  577. // div -> input type='file'
  578. removeNode(this._input.parentNode);
  579. removeClass(self._button, self._settings.hoverClass);
  580. removeClass(self._button, self._settings.focusClass);
  581. form.appendChild(this._input);
  582. form.submit();
  583. // request set, clean up
  584. removeNode(form); form = null;
  585. removeNode(this._input); this._input = null;
  586. // Get response from iframe and fire onComplete event when ready
  587. this._getResponse(iframe, file);
  588. // get ready for next request
  589. this._createInput();
  590. }
  591. };
  592. })();