Accueil Dev WEB

Jquery: upload en drag and drop

De retour pour un article, après quelque mois d’absence bien occupés au boulot ;)

Ici je vais vous parler de nouvelles possibilités javascript liées aux drag’n'drop ainsi qu’aux traitements de fichiers. Le but est de pouvoir drag’n'drop un fichier depuis votre explorateur de fichier, vers le navigateur, et d’en lancer ainsi un upload automatique avec suivi de progression, le tout en asynchrone ;)
Je vais d’ailleurs essayer de mettre un maximum de jQuery, comme à mon habitude ! J’aurais pu pousser le développement jusqu’à monter un plugin jQuery, mais finalement, à vous de jouer ;) Cet article n’a pas pour objectif de vous fournir une solution, mais plutôt de vous expliquer son fonctionnement. Vous avez des solutions toutes faites comme celui de valums ou celui de Aquantum (il en existe des tas d’autres).

Allez, une fois n’est pas coutume, une petite démo ! :D


    Pour des raisons de sécurité, vos fichiers ne sont bien sur pas réellement conservés sur mon serveur ;)

    Vous pouvez retrouver des démonstrations sur site en production sur Youtube et Gmail.

    Rentrons dans le vif du sujet. Nous allons décomposer cet outil en 3 grandes étapes:

    1. 1. Gérer un drag’n'drop de fichier vers le navigateur
    2. 2. Upload automatique du fichier
    3. 3. Gestion d’une barre de progression

    1. Gérer un drag’n'drop de fichier vers le navigateur

    Commençons par mettre en place une structure xHTML basique.

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.1.min.js"></script>
        <script type="text/javascript" src="ini_dnd.js"></script>
        <link rel="stylesheet" type="text/css" href="uploaddnd.css" />
    </head>
    <body>
        <div id="output">
            <ul id="output-listing"></ul>
        </div>
    </body>
    </html>
    

    Notre div#output sera notre élément xHTML prêt à accueillir un drop, et notre div#output-listing consistera en une liste textuelle des fichiers envoyés. N’hésitez pas à les styliser comme vous le souhaitez.
    Un script externe est appelé, ini_dnd.js , qui contient l’intégralité du code dont nous aurons besoin.

    La première étape est de déclarer les évènements liés au drop d’une entité, et de leur assigner des fonctions:

    $(document).ready(function(){
    
    	// On pose les évènements nécessaires au drag'n'drop
    	$('#output').bind({
    		"dragenter dragexit dragover" : do_nothing,
    		drop : drop
    	});
    
    });
    
    // Fonction stoppant toute évènement natif et leur propagation
    function do_nothing(evt){
    	evt.stopPropagation();
    	evt.preventDefault();
    }
    
    function drop(evt){
    	do_nothing(evt);
    	console.log('test');
    }
    

    Il est important de définir les 4 évènements liés au drag’n'drop, de façon à empêcher toute action native du navigateur. Le seul évènement qui nous intéresse pour notre application est « drop ». Les autres exécutent une fonction qui empêche l’action native navigateur.
    Remarquez la structure du bind, nous permettant d’utiliser une string pour assigner plusieurs évènements à la fois à la même fonction (pas grand chose à voir avec notre fonctionnalité, mais ca ravira les lecteurs qui ne connaissaient pas ;) ).

    On peut maintenant tester de drag’n'drop un fichier depuis notre système de fichier vers notre div#ouput. Cela fonctionne !

    2. Upload automatique du fichier

    Passons à l’upload asynchrone de notre fichier. Vous allez voir qu’il est possible de le réaliser entièrement grâce à jQuery, en modifiant un peu le comportement par défaut de notre librairie préférée ;) SEXY !

    Ce qui va nous permettre de récupérer les informations du fichier à partir de notre drag’n'drop, c’est la nouvelle propriété « dataTransfer » d’un objet Event. Bien sûr, cette propriété n’est pas comprise par tous les navigateurs (IE 9 ? :p). Et à ce titre, jQuery ne reconnait pas cette propriété dans ses propres objets Event. Heureusement, ils nous proposent de pouvoir accéder à toutes les propriétés fournies par le navigateur via la propriété « originalEvent » de leurs objets Event. Mais j’ai choisi une autre solution, que je trouve plus sympa: ajouter la propriété « dataTransfer » aux propriétés natives des Event. Et oui, c’est possible ! Via l’Array « props » de $.event , nous allons pouvoir y ajouter notre fameuse propriété. Modifions donc le document.ready :

    $(document).ready(function(){
    
    	// On ajoute la propriété spéciale dataTransfer à nos events jQuery
    	$.event.props.push("dataTransfer");
    
    	// On pose les évènements nécessaires au drag'n'drop
    	$('#output').bind({
    		"dragenter dragexit dragover" : do_nothing,
    		drop : drop
    	});
    
    });
    

    Puis, modifions la fonction « drop » pour nous afficher le contenu de notre propriété:

    function drop(evt){
    	do_nothing(evt);
    	console.log(evt.dataTransfer);
    }
    

    Nous récupérons bien toutes les propriétés souhaitées, en particulier evt.dataTransfer.files , notre Array de fichiers ! Il va maintenant falloir l’envoyer en POST sur un script côté serveur, afin de pouvoir l’enregistrer physiquement. Pour cela, il serait assez simple de passer directement par un objet XMLHttpRequest car jQuery ne le gère pas par défaut. Mais, comme à mon habitude, je veux le faire avec jQuery. Vous allez voir qu’il suffit simplement de modifier 2 options par défaut de la méthode $.ajax afin de transmettre des fichiers.
    Quoiqu’il arrive, nous allons utiliser l’objet FormData des spécifications « XMLHttpRequest Level 2″. Ce n’est pas un objet nouveau, celui-ci est même connu de IE (notre référence des bas-fonds).
    Voici notre fonction drop modifiée pour notre nouvelle fonctionnalité:

    function drop(evt){
    	do_nothing(evt);
    
    	var files = evt.dataTransfer.files;
    
    	// On vérifie que des fichiers ont bien été déposés
    	if(files.length>0){
    		for(var i in files){
    			// Si c'est bien un fichier
    			if(files[i].size!=undefined) {
    
                	var fic=files[i];
    
                    // On construit notre objet FormData
                    var fd=new FormData;
                    fd.append('fic',fic);
    
                    // Requete ajax pour envoyer le fichier
                    $.ajax({
                        url:'/tests/dnd/save_fic.php',
                        type: 'POST',
                        data: fd,
                        processData:false,
                        contentType:false
                    });
    
    				// On ajoute notre fichier à la liste
    				$('#output-listing').append('<li>'+files[i].name+'</li>');
    
    			}
    		}
    	}
    
    }
    

    Nous déclarons un nouveau FormData et nous y insérons notre objet File.

    Ensuite, afin de pouvoir envoyer en POST un fichier, il nous faut modifier 2 options par défaut dans l’appel à la méthode ajax:

    • processData:false
    • contentType:false

    Si l’on regarde le coeur de jQuery, la méthode ajax va traiter nos données avant de les envoyer. Hors, elle ne reconnait pas notre fichier. Nous lui demandons donc de ne pas traiter les données envoyées via notre option « processData ». Puis, pour la même raison, nous devons empêcher le moteur jQuery de déterminer et envoyer un content-type dans les headers.
    Nous n’avons plus qu’à passer notre FormData dans l’option « data », et le tour est joué. Voici ce que pourrait être le contenu de mon fichier /tests/dnd/save_fic.php :

    	$fic=$_FILES['fic'];
    
    	move_uploaded_file($fic['tmp_name'],$_SERVER['DOCUMENT_ROOT'].'/tests/dnd/'.$fic['name']);
    

    Vous pouvez tester, votre upload est fonctionnel !!! Il ne reste plus qu’à afficher une barre de progression dynamique afin d’informer l’utilisateur de l’avancement.

    3. Gestion d’une barre de progression

    Puisque notre script va être amené à gérer des uploads multiples et simultanés, il faut y penser de suite pour produire autant de barres de progression qu’il le faut. Voici l’exemple xHTML d’une barre de progression que nous utiliserons dans notre exemple:

    <div class="progress_bar loading"><div class="percent">0%</div></div>
    

    De la même façon que pour notre div#output , stylisez votre progressbar comme vous le souhaitez. Nous ajouterons cette barre dynamiquement via javascript, et le script gérera la modification de la width de .percent ainsi que son contenu HTML.

    Ensuite, nous allons préparer l’affichage de la progressbar, afin d’indiquer à l’utilisateur le bon fonctionnement de l’upload. Sous notre requête ajax, générons notre progressbar ainsi:

        // On prépare la barre de progression au démarrage
        var id_tmp=fic.size;
        $('#output').after('
    
    0%
    ');

    Ici je base l’id sur la taille, c’est certainement loin d’être la méthode la plus optimisée, mais vous n’aurez aucun mal à trouver un système plus fonctionnel ;)

    La barre de progression est maintenant mise en place. Il va falloir la modifier dynamiquement en fonction de la réponse du serveur au cours de l’upload. Encore une fois, jQuery n’étant pas prévu pour, il va nous falloir mettre en place une feinte afin de pouvoir ajouter ca via notre méthode ajax.
    Il faut savoir que par défaut, l’évènement « progress » est disponible sur un objet « XMLHttpRequest » via sa propriété « upload » : xhr.upload.addEventListener(‘progress’, function(){}); . Hors, jQuery ne nous permet pas d’accéder à cette propriété via les options de la méthode ajax. Par contre, la librairie nous fournie un moyen de récupérer ET utiliser un objet xhr personnalisé !!! Et c’est ce que nous allons faire ;)

        // On ajoute un listener progress sur l'objet xhr de jQuery
        xhr = jQuery.ajaxSettings.xhr();
        if(xhr.upload){
            xhr.upload.addEventListener('progress', function (e) {
                update_progress(e,fic);
            },false);
        }
        provider=function(){ return xhr; };
    
        $.ajax({
            url:'/tests/dnd/save_fic.php',
            type: 'POST',
            data: fd,
            xhr:provider,
            processData:false,
            contentType:false
        });
    

    Nous récupérons l’objet xhr, nous vérifions qu’il contient la propriété « upload » (suivant les navigateurs), et nous lui ajoutons notre évènement personnalisé ! Il suffit ensuite de passer ce nouvel objet xhr via l’option « xhr » de la méthode ajax.

    Lors du trigger de l’évènement « progress », j’exécute donc la fonction « update_progress », en lui passant en argument notre évènement, ainsi que notre fichier (pour pouvoir accéder à la bonne barre de progression! ;) ). Voici la définition de la fonction « update_progress », qui ne nécessite pas de commentaire particulier au vu de sa facilité:

    // Mise à jour de la barre de progression
    function update_progress(evt,fic) {
    
    	var id_tmp=fic.size;
    
    	if (evt.lengthComputable) {
    		var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
    		if (percentLoaded <= 100) {
    			$('#'+id_tmp+' .percent').css('width', percentLoaded + '%');
    			$('#'+id_tmp+' .percent').html(percentLoaded + '%');
    		}
    	}
    }
    

    Enfin, il ne nous reste plus qu'à compléter à 100% la barre de progression lorsque l'exécution du script est terminée. En effet, l'évènement "progress" ne sera pas trigger à la toute fin de l'upload. Ajoutons donc une simple fonction en callback de l'ajax:

        $.ajax({
            url:'/tests/dnd/save_fic.php',
            type: 'POST',
            data: fd,
            xhr:provider,
            processData:false,
            contentType:false,
            complete:function(data){
                $('#'+data.responseText+' .percent').css('width', '100%');
                $('#'+data.responseText+' .percent').html('100%');
            }
        });
    

    Cette fonction nécessite que l'on renvoie le nom du fichier que l'on vient d'uploader. Le script système pourrait donc devenir:

    	$fic=$_FILES['fic'];
    
    	move_uploaded_file($fic['tmp_name'],$_SERVER['DOCUMENT_ROOT'].'/tests/dnd/'.$fic['name']);
    
    	$id_tmp=filesize($fic['tmp_name']);
    	echo $id_tmp;
    

    Et voila, nous en avons terminé! L'outil est pleinement fonctionnel, amusez-vous bien avec !
    Vous pouvez retrouver mon exemple complet avec les sources sur ce lien démo.

    N'hésitez pas à me laisser vos commentaires sur tout ce qui pourrait être amélioré, ainsi que vos éventuels problèmes ou questions sur son fonctionnement et sa mise en place ;)

    A bientôt pour un nouvel article je l'espère!

    28 Commentaires

    1. epeedelorage
      11 décembre 2011 at 4 h 13 min

      Salut,

      Merci, ca m’a bien aidé même si je n’utilise pas jQuerry.

      Cependant j’ai le même bug que ds la démo au niveau des barres de progressions lorsqu’on drop plusieurs fichier à la fois : le % est actualisé sur la même barre !

      Via un console.log(fic); ds la fonction update_progress, on voit que c’est tjrs le même fichier qui est passé en paramètre… Une idée ?

    2. Renaud Feigenbaum
      13 décembre 2011 at 14 h 07 min

      Salut,
      Oui bien vu, j’ai un peu modifié le javascript pour répondre à ta problématique. Tu peux retrouver le nouvel exemple sur http://www.spiblog.fr/tests/dnd/index_nobugmulti.html .

      Grosso modo, on se sert maintenant entièrement de l’évènement progress pour update les barres de progression. Tout se déroule dans la fonction update_progress .
      Ceci pose un nouveau problème: ajoutons un fichier, puis via un nouveau drag’n'drop, ajoutons le même fichier. Une nouvelle barre de chargement apparait et l’ancienne n’est plus update. Il faudrait simplement ajouter un contrôle de fichier, qui vérifie avant de lancer l’upload que ce fichier n’a pas déjà été envoyé (via un Array tab_already_sended par exemple). Je te laisse faire, ce n’est pas très sorcier !

    3. Vianney
      28 février 2012 at 12 h 27 min

      Cet article est très instructeur !

    4. 18 avril 2012 at 17 h 30 min

      Bonjour, cet article est très bien fais. J’ai juste un problème, je n’arrive pas a traité les informations liés a l’upload de l’image. Mon image s’upload tout simplement pas.

    5. 18 avril 2012 at 17 h 36 min

      Je viens de résoudre le problème :)

      Franchement fabuleux

      Merci beaucoup

    6. Renaud Feigenbaum
      19 avril 2012 at 9 h 27 min

      Un plaisir :)

    7. 31 mai 2012 at 20 h 19 min

      Bonjour,
      Merci pour ce script et les explications ! Je tente de le faire fonctionner depuis un moment, l’upload semble fonctionner, la barre de progression se met à jour, montrant bien que l’upload est en cours, mais je ne comprends pas, mon objet $_FILES est vide lors de l’appel de la page qui traite le fichier après l’upload. J’ai vérifié plusieurs fois les noms de variable, j’ai regardé aussi du côté du enctype, mais rien à faire, mon objet reste vide… Une piste pour m’aider ?

    8. Renaud Feigenbaum
      4 juin 2012 at 11 h 14 min

      Bonjour Arnaud, êtes-vous sur d’avoir utilisé un objet « FormData » ? C’est lui qui indique que les données sont envoyées sous l’enctype « multipart/form-data ».
      Auriez-vous un lien online de votre test?

    9. 9 juin 2012 at 17 h 53 min

      Bonjour,
      Merci pour votre réponse. Oui j’utilisais bien un objet FormData, et j’ai fini par trouver d’ou venait l’erreur. J’avais bêtement remplacé l’appel a code.jquery.com par un appel à une version locale de jquery (1.4.2), qui visiblement ne prenait pas en charge les fonctions utilisées. Problème réglé donc, merci encore pour ce script formidable !

    10. Info
      11 juin 2012 at 17 h 01 min

      Bonjour, j’essaye de tester votre module d’upload mais j’ai une erreur : Notice: Undefined index: fic
      Avez-vous une idée ?
      Merci d’avance

    11. Renaud Feigenbaum
      11 juin 2012 at 17 h 26 min

      Bonjour, vous essayer de le tester depuis mon lien demo ou depuis une interface que vous avez vous-même mis en place?
      Si c’est l’option 2: avez-vous un lien à me communiquer?

    12. Info
      11 juin 2012 at 17 h 48 min

      Oui c’est l’option 2.
      Non désole pas de lien je travaille en local actuellement
      Mon erreur est que la variable $fic dans le php semble vide ou même indéfini…

    13. Renaud Feigenbaum
      12 juin 2012 at 10 h 11 min

      J’aurais tendance à penser au même problème que pour Arnaud: utilisez-vous une version de jQuery à jour? Utilisez-vous bien un objet FormData?
      Si vos deux réponses sont affirmatives, vous pouvez nous copier un var_dump de votre variable $_FILES .

    14. kamui.studio
      21 août 2012 at 19 h 54 min

      Merci !!

      Exactement ce dont j’avais besoin, à savoir une explication des fonctionnalités, plutôt qu’un plugin lâché sans commentaires.

      Encore Merci !!

    15. 15 octobre 2012 at 12 h 01 min

      Bonjour, merci beaucoup pour ces explications, cela m’a permis d’intégrer le drag n drop d’image dans le back office de mes site e-commerce.

      J’ai toutefois un petit soucis, lorsque que je drop une image pour la 2eme fois celle ci s’ouvre dans l’explorer, je suis obligé de recharger la page pour que cela fonction a nouveau.

      Une idée ?

      Merci d’avance.

    16. Renaud Feigenbaum
      15 octobre 2012 at 12 h 36 min

      Bonjour, puisqu’une fois le premier drop effectué, les prochains drop ne sont plus catch, il doit y avoir un procédé dans votre source qui soit unbind l’évènement, soit qui le bind pour une seule exécution.
      Pour vous aider sur cette hypothèse, vous pouvez me communiquer un lien de démo de votre application.
      Autre possibilité: une erreur JS dans le callback du drop pourrait provoquer l’instabilité présentée ici. Pour déterminer cela, un simple affichage d’une console (firebug par exemple) pendant tout le process vous fixera sur cette hypothèse!

    17. 5 novembre 2012 at 16 h 56 min

      Bonjour merci pour votre réponse, pour vous donner un lien de démo, je doit vous créer un compte sur ma boutique de dev.

      pourriez-vous me contactez par mail pour faire cela en privé ?

      Merci d’avance.

    18. 29 janvier 2013 at 16 h 59 min

      Just solved the multibar problem and it work like a charm

      just replace the progress function like that:
      if(xhr.upload){
      (function(fic) {
      xhr.upload.onprogress = function(e)
      {
      update_progress(e,fic);
      };
      }(fic));
      }

    19. 27 mars 2013 at 1 h 37 min

      Amazing article it helped me a lot,
      thanks

    20. 21 août 2014 at 13 h 09 min

      women roshe run black fluorescent green…

      latest nike air jordan For You.Discount and Top quality air jordan red will give you free and fast shipping to your door!…

    21. Kenvir
      23 janvier 2015 at 12 h 02 min

      Howdy just wanted to give you a brief heads up and let you know a few of the pictures aren?t loading correctly. I?m not sure why but I think its a linking issue. I?ve tried it in two different browsers and both show the same results. ;) , pharmacie en ligne ne cesse de me appeler http://2getmeds.com foreign online pharmacy reviews

    22. dj53p7q3dl
      24 janvier 2015 at 21 h 33 min

      i/c y a e r w/ z x j
      ugg boots uk sale Buy, sell or consign favorite luxury designers such as Louis Vuitton, Chanel, Prada, Gucci, St canada goose mens

      ugg kids uk Phoenix, AZ December 15, 2011 A Phoenix Police auction will be hosted by Auction Systems Auctioneers & Appraisers, Inc., featuring several high value pieces of jewelry on Saturday, December 17, 2011.The luxury jewelry items included in this auction, along with their replacement value, are: Gent’s Rolex Platinum 950 and Diamond Watch, $85,000.00 Gent’s Rolex 18K Yellow Gold and Stainless Steel Watch, $12,000.00 Lady’s Rolex 18K White Gold Silver Jubilee Datejust Watch, $27,000.00 Gent’s Cartier Roadster Wrist Watch, $10,000.00 Lady’s Cartier 18K White Diamond Cross Pendant with Neck Chain, $8,000.00 Lady’s Louis Vuitton 18K White Gold Diamond Ring, $4,500.00 Lady’s Gucci Stainless Steel Watch Accented by Diamonds, $2,700.00 Gent’s Mont Blanc Wrist Watch, $1,600.00 Gent’s Breitling Colt Chronograph Watch, $2,200.00 An auction is one of the few places nowadays where you can purchase beautiful and unique pieces of jewelry at reduced prices, said Deb Weidenhamer, CEO of Auction Systems’ Phoenix police auction. Whether you’re a first time buyer or discriminating collector, you’re likely to find items of interest at this upcoming auction. This police auction will be held on Saturday, December 17, 2011 at 9:00 a.m. at Auction Systems located at 951 W. Watkins in Phoenix, AZ. All of the items listed in the auction may be previewed and inspected by interested bidders on Thursday, December 15, 2011 from 4:00 p.m. to 6:00 p.m., Friday, December 16, 2011 from 10:00 a.m. to 2:00 p.m., and Saturday, December 17, 2011 from 8:00 a.m. to 9:00 a.m. one hour prior to auction.Items will also be available for preview and online bidding beginning Saturday, December 10, 2011. Interested parties can visit Auction Systems’ Phoenix auction schedule, to preview and sign up for online bidding. About Auction Systems Auctioneers & Appraisers, Inc.Auction Systems Auctioneers & Appraisers, Inc. is the Southwest’s most active auction and appraisal company. Auction Systems features live and live simulcast auctions and appraisals of stolen and confiscated Police and personal product including cars, tools, electronics, jewelry, sporting, coins and surplus, as well as auctions of commercial and heavy equipment, real estate, antiques, guns, estate and business liquidation and bankruptcy. Based in Phoenix, Arizona and an INC. 500 company, Auction Systems is one of the fastest growing privately held companies within the United States. Additionally, Auction Systems is an ICIC INC. 100 company and is ranked as the #1 fastest growing woman owned business and the fifteenth fastest growing business overall within the inner cities of the United States. Auction Systems Auctioneers & Appraisers, Inc. can be found on the web at auctionANDappraise.###AshLee Frazier’s ?€?Love It Store?€? Launches Online on October 1, 2013 barbour sale outlet

      uggs for sale Phoenix, AZ September 14, 2011 A Phoenix police auction, hosted by Auction Systems Auctioneers & Appraisers, Inc., will feature vehicles, jewelry, confiscated property, tools, city surplus, school district supplies and equipment, electronics, appliances, computers, commercial equipment, restaurant equipment, sporting goods, household items, furniture, and much more on Saturday, September 17, 2011.Items of interest for this Phoenix police auction include: Thomas Kinkade "Lamplight Village" custom framed lithograph, Android tablet, TomTom XL GPS system, purse marked Louis Vuitton Paris, autographed Journey drum head and concert set list, Zenith Wave Magnet Trans Oceanic short wave radio, Mitsubishi 62" DLP HD television, Sega Harley Davidson and L.A. Riders arcade game, Trek 7.3FX black bike, Craftsman 12" compound miter saw, Samsung 50" DLP television, Delta 50 860 commercial air cleaner, General Electric front loading washing machine, Miller Millermatic 251 MIG welder, Hobart 600 mixer with shredder head, Rock Well Delta jointer, Beverage Air commercial refrigerator and freezer, Ballys "Double Jackpot Double" slot machine, 1988 white and orange 1969 Camaro SS official pace car 12.5"x4" collectible car decanter, Photogenic professional lighting system including 1250 power light, StudioMax III 320, tripod, case and more, and a vintage "Drink Coca Cola" 25 cent bottle dispenser. Police auctions allow the general public an opportunity to purchase highly desirable items often at unbelievable discounts, said Deb Weidenhamer, CEO of Auction Systems’ Phoenix police auction. Whether you’re looking for resale inventory, a specific item or just a good deal, police auctions provide a fun and rewarding experience for all attendees. This police auction will be held on Saturday, September 17, 2011 at 9:00 a.m. at Auction Systems located at 951 W. Watkins in Phoenix, AZ. All of the items listed in the auction may be previewed and inspected by interested bidders on Thursday, September 15, 2011 from 4:00 p.m. to 6:00 p.m., Friday, September 16, 2011 from 10:00 a.m. to 2:00 p.m., and Saturday, September 17, 2011 from 8:00 a.m. to 9:00 a.m. one hour prior to auction.Items will also be available for preview and online bidding beginning Saturday, September 10, 2011. Interested parties can visit Auction Systems’ Phoenix auction schedule, to preview and sign up for online bidding. About Auction Systems Auctioneers & Appraisers, Inc.Auction Systems Auctioneers & Appraisers, Inc. is the Southwest’s most active auction and appraisal company. Auction Systems features live and live simulcast auctions and appraisals of stolen and confiscated Police and personal product including cars, tools, electronics, jewelry, sporting, coins and surplus, as well as auctions of commercial and heavy equipment, real estate, antiques, guns, estate and business liquidation and bankruptcy. Based in Phoenix, Arizona and an INC. 500 company, Auction Systems is one of the fastest growing privately held companies within the United States. Additionally, Auction Systems is an ICIC INC. 100 company and is ranked as the #1 fastest growing woman owned business and the fifteenth fastest growing business overall within the inner cities of the United States. Auction Systems Auctioneers & Appraisers, Inc. can be found on the web at auctionANDappraise.###Americana Manhasset Launches 2010 Holiday Portfolio and Video Lookbook belstaff sale mens

    23. 27 février 2015 at 5 h 02 min

      Does your site have a contact page? I’m having trouble locating it but, I’d like to send you an e-mail. I’ve got some suggestions for your blog you might be interested in hearing. Either way, great blog and I look forward to seeing it expand over time.

    24. 27 février 2015 at 15 h 21 min

      Simply want to say your article is as surprising. The clearness in your post is just excellent and i could assume you are an expert on this subject. Well with your permission allow me to grab your feed to keep up to date with forthcoming post. Thanks a million and please keep up the gratifying work.

    25. 26 mars 2015 at 23 h 32 min

      Take a look, before he changes it! His forums page is designed by military designs, a website design company that specializes in military websites. How pathetic, he still wants to be a part of the military!

    26. 19 avril 2015 at 7 h 11 min

      Thorn of Girl…

      Great data can be located on this website blogging site….

    27. 25 avril 2015 at 5 h 09 min

      The Birch of the Shadow…

      I believe there may possibly be considered a several duplicates, but an exceedingly helpful record! I’ve tweeted this. Lots of thanks for sharing!…

    28. 26 avril 2015 at 5 h 49 min

      I simply want to say I’m newbie to blogging and site-building and honestly loved you’re blog. More than likely I’m want to bookmark your website . You really come with fantastic articles. Kudos for revealing your website page.

    Ajouter un commentaire

    Votre Email n'est jamais publiée ou partagée. Les champs requis sont marqués *.

    *
    *