What is the best way to implement native DnD for RichTextArea?  I need to 
support users dropping items into the RichTextArea that originated from 
outside the browser (from another web app).

Currently what I have partially works (in production seems to work about 
50% of the time) in hosted mode it's only working on the first Drop (could 
be because of recent changes).  Currently we are doing this with JSNI. 
 I'll paste the full code below but the key parts are that on the drop 
event I need to get the 'text' data, e.g.

var data = event.dataTransfer.getData("Text");

Then I parse that data/URI and build a div which I then append to the 
original element.

Some of the things I'm not sure about are...what Document to be working 
with.  The original code used document in the JSNI method but I see online 
that $doc should be used.  Or I could pass into the JSNI method the 
document, e.g. 

 IFrameElement fe = getElement().cast();
 Document document = fe.getContentDocument();

Or ideally I'd prefer to do this with a more pure GWT solution and use less 
JSNI if that's possible.  How best to respond to these native drops?  Why 
would this code only be working for the first drop?  (Note, we have several 
instances of this widget in the application)  Here is the full code. (The 
first set of methods ininitDnD just parse URI...nothing interesting until 
the allowDrop/droppedHandler/addEvent methods)


// This will be called only once at startup.
    protected void onInitializeOnce() {
        super.onInitializeOnce();

        Document document = getContentDocument();
        BodyElement body = getBodyElement();
        initDnD(document, body);
    }

 private native void initDnD(Document document, Element elem) /*-{

        function strictEncodeURIComponent(string) {
            return encodeURIComponent(string).replace(/[!'()*]/g, escape);
        }

        encode = strictEncodeURIComponent;
        decode = decodeURIComponent;

        var parseURI = function (string) {
            var pos, t, parts = {};
            
            pos = string.indexOf('#');
            if (pos > -1) {
                // escaping?
                parts.fragment = string.substring(pos + 1) || null;
                string = string.substring(0, pos);
            }

            // extract query
            pos = string.indexOf('?');
            if (pos > -1) {
                // escaping?
                parts.query = string.substring(pos + 1) || null;
                string = string.substring(0, pos);
            }

            // extract protocol
            if (string.substring(0, 2) === '//') {
                // relative-scheme
                parts.protocol = '';
                string = string.substring(2);
                // extract "user:pass@host:port"
                string = parseURIAuthority(string, parts);
            } else {
                pos = string.indexOf(':');
                if (pos > -1) {
                    parts.protocol = string.substring(0, pos);
                    if (string.substring(pos + 1, pos + 3) === '//') {
                        string = string.substring(pos + 3);

                        // extract "user:pass@host:port"
                        string = parseURIAuthority(string, parts);
                    } else {
                        string = string.substring(pos + 1);
                        parts.urn = true;
                    }
                }
            }

            // what's left must be the path
            parts.path = string;

            // and we're done
            return parts;
        };
        var parseURIHost = function (string, parts) {
            // extract host:port
            var pos = string.indexOf('/'),
                    t;

            if (pos === -1) {
                pos = string.length;
            }

            if (string[0] === "[") {
                // IPv6 host - 
http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-04#section-6
                // I claim most client software breaks on IPv6 anyways. To 
simplify things, URI only accepts
                // IPv6+port in the format [2001:db8::1]:80 (for the time 
being)
                var bracketPos = string.indexOf(']');
                parts.hostname = string.substring(1, bracketPos) || null;
                parts.port = string.substring(bracketPos + 2, pos) || null;
            } else if (string.indexOf(':') !== string.lastIndexOf(':')) {
                // IPv6 host contains multiple colons - but no port
                // this notation is actually not allowed by RFC 3986, but 
we're a liberal parser
                parts.hostname = string.substring(0, pos) || null;
                parts.port = null;
            } else {
                t = string.substring(0, pos).split(':');
                parts.hostname = t[0] || null;
                parts.port = t[1] || null;
            }

            if (parts.hostname && string.substring(pos)[0] !== '/') {
                pos++;
                string = "/" + string;
            }

            return string.substring(pos) || '/';
        };
        var parseURIAuthority = function (string, parts) {
            string = parseURIUserinfo(string, parts);
            return parseURIHost(string, parts);
        };
        var parseURIUserinfo = function (string, parts) {
            // extract username:password
            var pos = string.indexOf('@'),
                    firstSlash = string.indexOf('/'),
                    t;

            // authority@ must come before /path
            if (pos > -1 && (firstSlash === -1 || pos < firstSlash)) {
                t = string.substring(0, pos).split(':');
                parts.username = t[0] ? decode(t[0]) : null;
                parts.password = t[1] ? decode(t[1]) : null;
                string = string.substring(pos + 1);
            } else {
                parts.username = null;
                parts.password = null;
            }

            return string;
        };
        var parseURIQuery = function (string) {
            if (!string) {
                return {};
            }

            // throw out the funky business - "?"[name"="value"&"]+
            string = string.replace(/&+/g, '&').replace(/^\?*&*|&+$/g, '');

            if (!string) {
                return {};
            }

            var items = {},
                    splits = string.split('&'),
                    length = splits.length;

            for (var i = 0; i < length; i++) {
                var v = splits[i].split('='),
                        name = encodeURIQuery(v.shift()),
                // no "=" is null according to 
http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#collect-url-parameters
                        value = v.length ? decodeURIQuery(v.join('=')) : 
null;

                if (items[name]) {
                    if (typeof items[name] === "string") {
                        items[name] = [items[name]];
                    }

                    items[name].push(value);
                } else {
                    items[name] = value;
                }
            }

            return items;
        };
        var encodeURIQuery = function (string) {
            return encode(string + "").replace(/%20/g, '+');
        };
        var decodeURIQuery = function (string) {
            return decode((string + "").replace(/\+/g, '%20'));
        };

        function allowDrop(event) {
            if (event.stopPropagation) {
                event.stopPropagation();
            }
            if (event.preventDefault) {
                event.preventDefault();
            }
            return false;
        }

        function droppedHandler(event) {
            // Try to use the 'text' everytime.
            try {
                alert("event= " + event);
                var data = event.dataTransfer.getData("Text");
                alert("data=" + data);
                if (data != null && data != "") {
                    try {
                        var parsedURI = parseURI(data);
                        var urlParameters = parseURIQuery(parsedURI.query);
                        var appsrc = urlParameters['appsrc'];
                        if (appsrc != null && appsrc == "COREFX") {
                            try {
                                // For some versions of IE, need to do this 
to prevent duplicates.
                                event.dataTransfer.setData('Text', '');
                            }
                            catch (e) {
                            }

                            if (event.preventDefault) {
                                event.preventDefault();
                            }

                            var title = data;
                            if (urlParameters['title'] != null) {
                                title = urlParameters['title'];
                            }
                            var newContentWrapper = 
document.createElement('div');
                            newContentWrapper.setAttribute('draggable', 
true);
                            newContentWrapper.setAttribute('ondragstart', 
"dragStart(event)");

                            var newContent = document.createElement('a');
                            newContent.setAttribute('href', data);
                            newContent.setAttribute('class', 
"external_system");

                            if (urlParameters['icon'] != null) {
                                var icon = decodeURI(urlParameters['icon']);
                                var newContentIcon = 
document.createElement('img');
                                newContentIcon.setAttribute('src', icon);
                                newContent.appendChild(newContentIcon);
                            }

                            var newContentTitle = 
document.createTextNode(title);
                            newContent.appendChild(newContentTitle);

                            newContentWrapper.appendChild(newContent);
                            var targetElement = event.target || 
event.srcElement;
                            targetElement.appendChild(newContentWrapper);
                            return false;
                        }
                    }
                    catch (e) {
                    }
                }
            }
            catch (error) {
            }
            return true;
        }

        var addEvent = (function () {
            if (document.addEventListener) {
                return function (el, type, fn) {
                    if (el && el.nodeName || el === window) {
                        el.addEventListener(type, fn, false);
                    } else if (el && el.length) {
                        for (var i = 0; i < el.length; i++) {
                            addEvent(el[i], type, fn);
                        }
                    }
                };
            } else {
                return function (el, type, fn) {
                    if (el && el.nodeName || el === window) {
                        el.attachEvent('on' + type, function (eventParam) {
                            if (!eventParam) {
                                eventParam = window.event;
                            }
                            return fn.call(el, eventParam);
                        });
                    } else if (el && el.length) {
                        for (var i = 0; i < el.length; i++) {
                            addEvent(el[i], type, fn);
                        }
                    }
                };
            }
        })();
        addEvent(elem, 'drop', droppedHandler);
        addEvent(elem, 'dragover', allowDrop);
    }-*/;

-- 
You received this message because you are subscribed to the Google Groups 
"Google Web Toolkit" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to