केस स्टडी - Chrome में डाउनलोड को खींचें और छोड़ें

शुरुआती जानकारी

खींचें और छोड़ें (DnD), HTML 5 की कई बेहतरीन सुविधाओं में से एक है और यह Firefox 3.5, Safari, Chrome और IE में समर्थित है. Google ने हाल ही में एक नई सुविधा रोल आउट की है. इससे Google Chrome के उपयोगकर्ता, फ़ाइलों को ब्राउज़र से खींचकर डेस्कटॉप पर छोड़ सकते हैं. यह एक बहुत ही सुविधाजनक सुविधा है, लेकिन जब तक रायन सेडन ने इस नई सुविधा पर रिवर्स इंजीनियरिंग की खोजों के बारे में एक लेख पोस्ट नहीं किया, तब तक इसके बारे में लोगों को नहीं पता था.

Box.net पर हम इस बात से बहुत उत्साहित हैं कि कैसे इन नई सुविधाओं से, हम अपने क्लाउड कॉन्टेंट मैनेजमेंट टूल को बेहतर बना पा रहे हैं. साथ ही, डेवलपर समुदाय को ज़्यादा से ज़्यादा योगदान दे रहे हैं. मुझे यह बताते हुए खुशी हो रही है कि डीएनडी डाउनलोड को हमारे प्रॉडक्ट में इंटिग्रेट कर दिया गया है. अब Box का इस्तेमाल करने वाले लोग, फ़ाइलों को सीधे Chrome ब्राउज़र से खींचकर अपने डेस्कटॉप पर डाउनलोड और सेव कर सकते हैं.

हम आपको बताना चाहते हैं कि इस नई सुविधा के डेवलपमेंट के दौरान, मैंने कई बार जांच की.

देखें कि खींचें और छोड़ें एपीआई की सुविधा उपलब्ध है या नहीं

सबसे पहले यह जांच लें कि आपका ब्राउज़र HTML5 खींचें और छोड़ें की सुविधा के साथ पूरी तरह काम करता हो. ऐसा करने का सबसे आसान तरीका है कि किसी खास सुविधा की जांच करने के लिए, Modernizr नाम की लाइब्रेरी का इस्तेमाल करना:

if (Modernizr.draganddrop) {
// Browser supports native HTML5 DnD.
} else {
// Fallback to a library solution.
}

इटरेशन 1

मैंने पहली बार वह तरीका आज़माया जो सिडडॉन को Gmail में मिला. मैंने फ़ाइलों के ऐंकर लिंक में 'data-downloadurl' नाम का एक नया एट्रिब्यूट जोड़ा है. इस प्रोसेस में, HTML5 के कस्टम डेटा एट्रिब्यूट का इस्तेमाल किया जाता है. data-downloadurl में, आपको फ़ाइल का MIME टाइप, डेस्टिनेशन फ़ाइल का नाम (डाउनलोड की गई फ़ाइल का पसंदीदा फ़ाइल नाम), और फ़ाइल का डाउनलोड यूआरएल शामिल करना होगा. इसलिए, इसे एचटीएमएल टेंप्लेट में जोड़ दिया जाता है:

<a href="#" class="dnd"
data-downloadurl="{$item.mime}:{$item.filename}:{$item.url}"></a>

जिससे नीचे दिए गए तरीके से आउटपुट बनेगा:

<a href="#" class="dnd" data-downloadurl=
"image/jpeg:Penguins.jpg:https://www.box.net/box_download_file?file_id=f66690"></a>

वॉन Schorsch ने Seddon के लेख पर आधारित jQuery plugin के आधार पर, एक jQuery प्लगिन जोड़ा है. यह ब्राउज़र की कुछ सुविधाओं का पता लगाने का काम करता है. यहां वे पंक्तियां हाइलाइट की गई हैं जिन्हें मैंने वॉन शॉर्स के वर्शन में जोड़ा था:

(function($) {

$.fn.extend({
dragout: function() {
var files = this;
if (files.length > 0) {
    $(files).each(function() {
    var url = (this.dataset && this.dataset.downloadurl) ||
                this.getAttribute("data-downloadurl");
    if (this.addEventListener) {
        this.addEventListener("dragstart", function(e) {
        if (e.dataTransfer && e.dataTransfer.constructor == Clipboard &&
            e.dataTransfer.setData('DownloadURL', 'http://www.box.net')) {
            e.dataTransfer.setData("DownloadURL", url);
        }
        },false);
    }
    });
}
}
});

})(jQuery);

मैंने ऐसा इसलिए किया क्योंकि ब्राउज़र की पहले की पहचान के बिना, IE में एचटीएमएल एलिमेंट में addEventListener() का इस्तेमाल करने से JavaScript गड़बड़ी पैदा होगी, क्योंकि IE में अपने अटैच करने के तरीके का इस्तेमाल किया जाएगा. जैसे, IE में e.dataTransfer. Safari में, e.dataTransfer.setData('DownloadURL','http://www.box.net') 'गलत' दिखाता है और Chrome इस स्टेटमेंट के लिए 'सही' दिखाता है. ऊपर बताए गए सभी जांच करने पर, यह सुविधा सिर्फ़ Chrome पर उपलब्ध रहती है. आप कह सकते हैं कि मैं बस ये काम कर सकता हूं:

/chrome/.test( navigator.userAgent.toLowerCase() )

मुझे ब्राउज़र की पहचान करने की सुविधा के बजाय, सुविधा की पहचान करना पसंद है. हालांकि, तकनीकी तौर पर यह पता नहीं चलता कि डीएनडी डाउनलोड काम करेगा.

इटरेशन 1 के सवाल

1) फ़िलहाल, हमारे पेज पर मौजूद DnD की सुविधा चालू है. इसलिए, हम एक फ़ोल्डर से दूसरे फ़ोल्डर में फ़ाइल ले जा सकते हैं या उसे कॉपी कर सकते हैं. इसलिए, हमें DnD डाउनलोड और पेज पर मौजूद DnD में अंतर करने के लिए कोई तरीका चाहिए. तकनीकी रूप से, हम इन दोनों कार्रवाइयों को एक साथ नहीं जोड़ सकते. हम यह अनुमान नहीं लगा सकते कि उपयोगकर्ता, Box.net खाते में मौजूद किसी फ़ाइल को किसी दूसरे फ़ोल्डर में ले जाना चाहता है या उसे खींचकर अपने डेस्कटॉप पर छोड़ना चाहता है. ये दोनों कार्रवाइयाँ पूरी तरह से अलग हैं. इसके अलावा, यह पता लगाने का कोई आसान तरीका नहीं है कि कर्सर ब्राउज़र विंडो से बाहर है या नहीं. माउसआउट इवेंट को दस्तावेज़ से अटैच करने के लिए, window.onmouseout (IE) और document.onmouseout (अन्य ब्राउज़र) का इस्तेमाल किया जा सकता है. साथ ही, यह भी देखा जा सकता है कि e.relatedTarget.nodeName == "HTML" (e, माउसआउट इवेंट या window.event है, जो भी उपलब्ध हो). हालांकि, इवेंट बबलिंग की वजह से ऐसा करना काफ़ी मुश्किल है. जब कोई इमेज या लेयर, खास तौर पर Box.net जैसे कॉम्प्लेक्स वेब ऐप्लिकेशन पर हो, तो इवेंट किसी भी क्रम में ट्रिगर हो सकता है.

2) हम चाहते हैं कि उपयोगकर्ता साफ़ तौर पर कुछ ऐसा करे, जिससे वह गलती से किसी चीज़ को डेस्कटॉप पर खींचकर बाहर ले जाने से रोक दे. किसी Box फ़ोल्डर का संपादक एक ऐसी एक्ज़ीक्यूटेबल फ़ाइल को अपलोड कर सकता है जो उसे डाउनलोड करने वाले के कंप्यूटर पर अनचाहे तरीके से काम करती है. हम चाहते हैं कि उपयोगकर्ता को ठीक से पता चल जाए कि फ़ाइल डेस्कटॉप पर कब डाउनलोड होगी.

इटरेशन 2

हमने कंट्रोल और ड्रैग (Windows Ctrl बटन दबाने पर फ़ाइल को ड्रैग करने) के साथ प्रयोग करने का फ़ैसला किया है. यह कार्रवाई वही है जो लोग किसी फ़ाइल की डुप्लीकेट कॉपी बनाने के लिए, Windows डेस्कटॉप पर कर सकते हैं. साथ ही, फ़ाइलों को गलती से डाउनलोड होने से रोकने के लिए, आपको उपयोगकर्ता को ज़्यादा मेहनत करनी पड़ती है, न कि अतिरिक्त चरण.

इटरेशन 1 में jQuery प्लगिन को अब छोड़ दिया गया है, क्योंकि हमें DnD Download को ऑन-पेज डीएनडी के साथ पूरी तरह इंटिग्रेट करना होगा. जिन लोगों को इसमें दिलचस्पी है उनके लिए, हम jQuery यूज़र इंटरफ़ेस के खींचने लायक प्लगिन के बदले गए वर्शन का इस्तेमाल करते हैं. टारगेट एलिमेंट के माउसडाउन इवेंट में, हमने यह कोड डाला है:

// DnD to desktop when the Ctrl key is pressed while dragging
if (e.ctrlKey) {
var that = $(e.target);
// make sure it is not IE (attachEvent).
if (that[0].addEventListener) {
    that[0].addEventListener("dragstart",function(e) {
        // e.dataTransfer in Firefox uses the DataTransfer constructor
        // instead of Clipboard
        // make sure it's Chrome and not Safari (both webkit-based).
        // setData on DownloadURL returns true on Chrome, and false on Safari
        if (e.dataTransfer && e.dataTransfer.constructor == Clipboard &&
            e.dataTransfer.setData('DownloadURL','http://www.box.net')) {
        var url = (this.dataset && this.dataset.downloadurl) ||
                    this.getAttribute("data-downloadurl");
        e.dataTransfer.setData("DownloadURL", url);
        }
    }, false);
    return;
}
}

Ctrl बटन को चालू करने के अलावा, हमने टोस्टर के लिए एक छोटा टूलटिप जोड़ा. यह तब दिखता है, जब उपयोगकर्ता पेज पर बार-बार खींचता है. यह उपयोगकर्ता को बताता है कि अगर Ctrl बटन को दबाकर रखते हुए फ़ाइल आइकॉन को डेस्कटॉप पर खींचा जाता है, तो फ़ाइलें डाउनलोड की जा सकती हैं.

इटरेशन 2 के सवाल

सुरक्षा से जुड़ी समस्याओं की वजह से, Box.net स्टैटिक फ़ाइलों को सीधे ऐक्सेस करने के लिए स्थायी यूआरएल नहीं दिखाता. यह सिर्फ़ Box.net से जुड़ा नहीं है. किसी भी ऑनलाइन स्टोरेज सेवा को सुरक्षा की एक और लेयर के बिना स्थायी यूआरएल नहीं दिखने चाहिए. इससे यह पता किया जा सकता है कि फ़ाइल सार्वजनिक है या नहीं. साथ ही, यह भी देखना चाहिए कि उपयोगकर्ता ने सही अनुमति वाले ऐप्लिकेशन को डाउनलोड करने का अनुरोध किया है या नहीं.

किसी आइटम के "डाउनलोड यूआरएल" (जैसे कि https://www.box.net/box_download_file?file_id=f_60466690) का पालन करने पर, यह "302 मिला" स्टेटस कोड दिखाता है और किसी रैंडम यूआरएल (जैसे कि https://www.box.net/dl/6045?a=1f1207a084&m=168299,11211&t=2&b=aca15820d924e3b) पर रीडायरेक्ट कर देता है, जो फ़ाइल का अस्थायी "असल यूआरएल" होता है. चुनौती यह है कि यह हर कुछ मिनट में खत्म हो जाता है और इसलिए इसे एचटीएमएल आउटपुट में डालना संभव नहीं है. जब उपयोगकर्ता कई मिनट पहले जनरेट किए गए एचटीएमएल आउटपुट में लिंक से फ़ाइल डाउनलोड करने की कोशिश करता है, तो "404" गड़बड़ी मिल सकती है.

DnD डाउनलोड सिर्फ़ उन असल यूआरएल पर काम करता है जो सीधे किसी संसाधन पर ले जाते हैं. अगर रीडायरेक्शन शामिल है, तो फ़िलहाल यह चेन को फ़ॉलो करने के लिए काफ़ी स्मार्ट नहीं है (और सुरक्षा की वजह से इसे कभी भी चेन का पालन नहीं करना चाहिए). हालांकि, ऊपर दिए गए लिंक https://www.box.net/box_download_file?file_id=f_60466690 से, आपको इस फ़ाइल को ब्राउज़र के लोकेशन बार में डालने पर, इसे डाउनलोड करने की सुविधा मिलती है. हालांकि, यह डीएनडी के साथ काम नहीं करेगी.

"असल यूआरएल" और "रीडायरेक्ट यूआरएल" के बीच के अंतर को बेहतर तरीके से समझाने के लिए, स्क्रीनशॉट देखें:

302 रीडायरेक्ट यूआरएल
302 रीडायरेक्ट यूआरएल
सही यूआरएल
असल यूआरएल

इटरेशन 3

चलिए, Ajax आज़माते हैं.

हमने पिछले वर्शन में कोड में थोड़ा बदलाव किया था और यह बना दिया है:

// DnD to desktop when the Ctrl key is pressed while dragging
if (e.ctrlKey) {
var that = $(e.target);
// make sure it is not IE (attachEvent).
if (that[0].addEventListener) {
that[0].addEventListener("dragstart", function(e) {
    // e.dataTransfer in Firefox uses the DataTransfer constructor
    // instead of Clipboard
    // make sure it's Chrome and not Safari (both webkit-based).
    // setData on DownloadURL returns true on Chrome, and false on Safari
    if (e.dataTransfer && e.dataTransfer.constructor == Clipboard &&
        e.dataTransfer.setData('DownloadURL', 'http://www.box.net')) {
    var url = (this.dataset && this.dataset.downloadurl) ||
                this.getAttribute("data-downloadurl");
    $.ajax({
        complete: function(data) {
        e.dataTransfer.setData("DownloadURL", data.responseText);
        },
        type:'GET',
        url: url
    });
    }
}, false);
return;
}
}

यह समझ में आता है. ड्रैगस्टार्ट करने पर, यह सर्वर को तुरंत एक Ajax कॉल करता है, ताकि फ़ाइल का सबसे नया डाउनलोड यूआरएल वापस पाया जा सके. हालांकि, यह काम नहीं करता है.

बाद में पता चला कि इसे एक सिंक्रोनस कॉल की ज़रूरत है (या जैसा कि मैं इसे Sjax कहता हूँ). ऐसा लगता है कि इवेंट लिसनर अटैच होने पर, setData को पूरा करना होता है. jQuery के API के अनुसार, हाइलाइट की गई लाइनें ये हो जाती हैं:

$.ajax({
async: false,
complete: function(data) {
e.dataTransfer.setData("DownloadURL", data.responseText);
},
type: 'GET',
url: url
});

यह तब तक ठीक रहेगा, जब तक कि मैं नेटवर्क कनेक्शन को अनप्लग न कर दूं. ब्राउज़र, सिंक्रोनस कॉल करता है. इसलिए, कॉल पूरा होने तक ब्राउज़र फ़्रीज़ हो जाता है. अगर Ajax कॉल फ़ेल हो जाता है (404 या वह बिलकुल भी जवाब नहीं देता), तो ब्राउज़र ऐसा बिलकुल भी डिफ़्रॉस्ट नहीं करेगा, जैसे कि वह क्रैश हो गया हो.

नीचे दिए गए तरीके इस्तेमाल करना ज़्यादा सुरक्षित है:

$.ajax({
async: false,
complete: function(data) {
e.dataTransfer.setData("DownloadURL", data.responseText);
},
error: function(xhr) {
if (xhr.status == 404) {
    xhr.abort();
}
},
type: 'GET',
timeout: 3000,
url: url
});

इस सुविधा का डेमो देखने के लिए, Box.net खाते में कोई स्टैटिक फ़ाइल अपलोड करें. Ctrl बटन दबाकर रखते हुए फ़ाइल आइकॉन को बाहर की ओर अपने डेस्कटॉप पर खींचें और छोड़ें. अगर आपके पास कोई खाता नहीं है, तो एक खाता बनाने में 30 सेकंड से भी कम समय लगता है.

इस सुविधा की मदद से, क्रिएटिविटी दिखाकर बहुत कुछ किया जा सकता है. किसी चित्र को Windows प्रिंटर संवाद में खींचने से चित्र तुरंत प्रिंट हो जाएगा. आप Box से किसी गाने को अपने मोबाइल फ़ोन के ड्राइव में कॉपी कर सकते हैं, सीधे अपने दोस्त को ट्रांसफ़र करने के लिए Box से किसी फ़ाइल को खींचकर अपने IM क्लाइंट में ले जा सकते हैं... इससे आपकी उत्पादकता बढ़ाने की अनगिनत संभावनाएं मिलती हैं.

किसी फ़ाइल को प्रिंटर के लिए रैग करना
फ़ाइल को प्रिंटर में खींचें और छोड़ें.
फ़ाइल को IM क्लाइंट में खींचना
IM क्लाइंट में फ़ाइल को खींचकर छोड़ना.

विचार और आने वाले समय में किए जाने वाले सुधार

हालांकि, ऐसा करना अब भी सही नहीं है, क्योंकि सिंक्रोनस कॉल, ब्राउज़र को कुछ समय के लिए लॉक कर सकता है. एचटीएमएल 5 वेब वर्कर भी कोई मदद नहीं करता, क्योंकि वेब वर्कर को एसिंक्रोनस होना चाहिए. ऐसा लगता है कि इवेंट लिसनर अटैच होने पर, setData को पूरा करना होता है.

असल में, परफ़ॉर्मेंस काफ़ी हद तक स्वीकार की जाती है. सिंक्रोनस Ajax (Sjax) कॉल सिर्फ़ एक यूआरएल स्ट्रिंग हासिल करता है, जो बहुत तेज़ होनी चाहिए. यह एचटीटीपी हेडर में बड़े ओवरहेड के साथ आता है, जिसे WebSockets इस्तेमाल करके ठीक किया जा सकता है. हालांकि, जब तक हम इस तरह की टेक्नोलॉजी का ज़्यादा इस्तेमाल नहीं देखते, तब तक क्लाइंट को हर छोटा अपडेट भेजने के लिए WebSockets इस्तेमाल करने का कोई फ़ायदा नहीं है.

मुझे उम्मीद है कि आने वाले समय में, इस एपीआई में एक से ज़्यादा फ़ाइल डाउनलोड करने की सुविधा जोड़ दी जाएगी. उपयोगकर्ता इंटरफ़ेस पर कई फ़ाइलें चुनने के लिए इसे कस्टम चेकबॉक्स के साथ जोड़ना, बेहतरीन होगा. साथ ही, अगर क्लाइंट की बनाई गई फ़ाइलें, जैसे कि सबमिट किए गए फ़ॉर्म के नतीजे से जनरेट की गई टेक्स्ट फ़ाइलें इस तरीके से डाउनलोड की जा सकती हैं, तो यह और भी अच्छा होगा.

  • कॉलम dnd
  • सूची को फिर से व्यवस्थित करें
  • इमेज गैलरी बनाना
  • कैनवस इमेज एक्सपोर्ट की जा रही है

रेफ़रंस