eads@3: /* 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@12: * $('img.my-class').dnd({targets: $('#my-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@16: * consistently across 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@16: * with a processIframeDrop appropriate to their editor. eads@3: * eads@16: * processTextAreaDrop: 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@12: * interval: eads@12: * How often to check the iframe for a drop, in milliseconds. eads@12: * eads@16: * eads@16: * 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@16: * When DnD is initialized, it begins timers which periodically check 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: * DnD is purely a utility library: to make it work for any particular editor, eads@16: * CMS, etc: It is very unlikely it will provide much benefit out of the box. 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@16: processIframeDrop: function(target, dragged, dropped, representation_id) { eads@3: // Keep a counter of how many times this element was used eads@3: var count = $.data(target, representation_id +'_count'); eads@3: if (!count) { eads@3: count = 1; eads@3: } else { eads@3: count++; eads@3: } eads@3: $.data(target, representation_id +'_count', count); eads@16: $(dropped).replaceWith('
' + representation_id + '
'); eads@3: }, eads@16: processTextAreaDrop: function(target, clicked, representation_id, e, data) { eads@16: var snippet = '