eads@20: /** eads@20: * jQuery Drag and Drop Library for Rich Editors eads@3: * eads@12: * A helper library which provides the ability to drag and drop images to Rich eads@16: * Text Editors (RTEs) that use the embedded iframe + DesignMode method. DnD eads@16: * also provides a simple "clicky" interface for inserting the same markup eads@16: * directly into a textarea. eads@3: * eads@3: * Basic usage: eads@3: * eads@20: * $('img.my-draggable-class').dnd({targets: $('#my-rte-iframe')}); eads@3: * eads@3: * Options: eads@3: * eads@16: * targets (Required): eads@16: * A jQuery object corresponding to the proper iframe(s) and/or textarea(s) eads@16: * that are allowed drop targets for the current set of elements. eads@3: * eads@16: * idSelector: eads@16: * A callback that parses out the unique ID of an image that is dropped in an eads@16: * iframe. While some browsers (such as Firefox and Internet Explorer) allow eads@16: * markup to be copied when dragging and dropping, Safari (and assumably eads@16: * other webkit based browsers) don't. The upshot is that the safest bet is eads@16: * to parse the element's src URL. Because querystrings seem to drop eads@20: * consistently across browsers, encoding the id in a query string is a good eads@20: * option. eads@3: * eads@16: * processIframeDrop: eads@16: * A callback that defines the mechanism for inserting and rendering the eads@16: * dropped item in an iframe. The typical usage pattern I expect to see is eads@16: * that implementers will listen for their RTE to load and then invoke DnD eads@20: * with a processIframeDrop appropriate to their editor. For performance eads@20: * reasons, this only runs once per invocation of DnD -- to compensate, we eads@20: * must pass in an idselector callback as an argument. eads@3: * eads@20: * processTextAreaClick: eads@16: * A callback that defines the mechanism for inserting and rendering the eads@16: * clicked item in a textarea. The default function just tries to insert eads@16: * some markup at the caret location in the current textarea. eads@3: * eads@20: * iframeTargetClass: eads@20: * A class to add to a draggable item if it can be dragged to an iframe. eads@20: * eads@20: * textareaTargetClass: eads@20: * A class to add to a draggable item if it can be dragged to a textarea. eads@20: * eads@24: * processedClass: eads@20: * A class to add to draggable items processed by DnD. eads@20: * eads@24: * droppedClass: eads@24: * A class to add to images that are dropped (by default, this is used to eads@24: * ensure that a successful drop manifests the editor representation only eads@24: * once.) eads@24: * eads@12: * interval: eads@12: * How often to check the iframe for a drop, in milliseconds. eads@12: * eads@12: * Usage notes: eads@12: * eads@16: * Due to cross browser flakiness, there are many many limitations on what is eads@16: * possible in terms of dragging and dropping to DesignMode enabled iframes. eads@12: * eads@16: * To make this work, your "droppable" elements must be image tags. No ifs, ands, eads@16: * or buts: image tags have the best cross browser behavior when dragging. eads@12: * eads@20: * When DnD is invoked, it begins a timer which periodically checks your eads@16: * editor iframe. If an image is dropped in, DnD takes the element and eads@16: * attempts to parse it for a unique ID which you can use to do a lookup for eads@16: * an "editor representation." If an editor representation is found, eads@16: * typically the image is replaced with the representation snippet, but you are eads@16: * free to do whatever you want. eads@12: * eads@16: * Because of browser limitations, the safest way to parse the element is to eads@16: * look at the img's src attribute and use some or all of the image URL. eads@16: * In my experience, the best way to deal with this is simply to parse out eads@16: * generate a query string in the src attribute server side that corresponds eads@16: * to the proper representation ID. eads@12: * eads@16: * If the target is not an iframe but a textarea, DnD provides a very minimal eads@16: * system for clicking what would otherwise be dragged to insert markup into eads@16: * the textarea. eads@16: * eads@16: * Because DnD spawns so many timers, they are stored in a $.data element eads@16: * attached to the parent document body. Implementers should consider clearing eads@16: * the timers when building systems such as dynamic searches or paging eads@16: * functionality to ensure memory usage and performance remains stable. eads@3: */ eads@3: eads@3: (function($) { eads@3: $.fn.dnd = function(opt) { eads@3: opt = $.extend({}, { eads@15: interval: 250, eads@16: targets: $('iframe, textarea'), eads@3: processTargets: function(targets) { eads@3: return targets.each(function() { eads@15: $('head', $(this).contents()).append(''); eads@3: return this; eads@3: }); eads@3: }, eads@3: idSelector: function(element) { eads@12: if ($(element).is('img')) { eads@16: return element.src; eads@3: } eads@16: return false; eads@3: }, eads@20: processIframeDrop: function(drop, id_selector) { eads@20: var representation_id = opt.idSelector(drop); eads@24: $(drop).replaceWith(representation_id).wrap('
'); eads@3: }, eads@20: processTextAreaClick: function(target, clicked, representation_id) { eads@16: var snippet = '