PageSourceSearch

https://marc-bloch.ehess.fr/js/jalios/core/jalios-sortable.js

js ehess.fr collected 2026-09-24 08:40:05 UTC 12,431 bytes, 349 lines download raw bytes

1!function ($) {
2
3  // ------------------------------------------
4  //  PRIVATE
5  // ------------------------------------------
6
7  var register = function(){
8    setup();
9    $(document).on('jalios:refresh', callback);
10  }
11  
12  var callback = function(event){
13  
14    var refresh = $.jalios.Event.match(event, 'refresh', 'after')
15    if (!refresh){ return; }
16    if (!refresh.target){ return; }
17    
18    setup(refresh.target);
19  }
20  
21  var setup = function($container){
22    
23    $container = $container || $(document);
24    
25    // Handle generic drag and drop lists
26    $container.find('UL.sortable, OL.sortable').each(function(){
27      $.jalios.Sortable.buildSortable(this, {
28        'connectWith' : $(this).attr('data-jalios-sortable-connect')
29      });
30    }); 
31    
32    var clazz = 'sortable-active';
33    
34    // Handle generic drag and drop container
35    $container.find('DIV.dnd-container').each(function(){
36      var $this = $(this);
37      var axis = $this.hasClass('dnd-horizontal') ? 'x' : $this.hasClass('dnd-vertical') ? 'y' : false;
38      $.jalios.Sortable.buildSortable(this, {
39        'items': '> DIV',
40        'axis': axis,
41        'revert': true,
42        'handle': '.dnd-header, .dnd-handle',
43        'placeholder' : 'dnd-placeholder',
44        'connectWith': $this.hasClass('dnd-single') || axis ? false : 'DIV.dnd-container'
45      });
46    });
47  }
48  
49  var hover = function(sortable, on){
50    var $this = $(sortable);
51    if ( on &&  $this.hasClass('sortable-active')){ return; }
52    if (!on && !$this.hasClass('sortable-active')){ return; }
53    $this.toggleClass('sortable-active', on);
54  }
55  
56  var trigger = function(that, ui){
57
58    var $that = $(that);
59
60    if ($that.hasClass('dnd-debug')) {
61      // http://stackoverflow.com/questions/3492828/jquery-sortable-connectwith-calls-the-update-method-twice
62      if (that === ui.item.parent()[0]) {   
63        // the movement was from one container to another, ui.sender is the reference to original container
64        if (ui.sender !== null) {
65          jQuery.console.log('[jalios-sortable]', ' item' , ui.item, ' moved from container', ui.sender, ' to ', $that);
66        }
67        // the move was performed within the same container
68        else {      
69          jQuery.console.log('[jalios-sortable]', ' item ', ui.item, ' moved inside container', $that);
70        }   
71      }
72    }
73    
74    // If dnd-single-update was specified on container, 
75    // Only send one 'jalios:sortable' and DataBroker event for all 'update' event sent by jQuery sortable,
76    // merging all container parameters at once 
77    var singleDndUpdate = $that.hasClass('dnd-single-update');
78    if (singleDndUpdate && that !== ui.item.parent()[0]) {
79      return;
80    }
81
82    // Trigger a document Event
83    var event = jQuery.Event("jalios:sortable");
84    event.sortable = {
85      'container' : $that,
86      'ui' : ui
87    };
88    $(document).trigger(event);
89    
90    // Trigger DataBroker Event
91    var serialize = $.jalios.Sortable.serialize($that, $that.hasClass('dnd-container') ? 'dnd-sortable' : false);
92    
93    // for single update event, also include the serialization of the sender container
94    if (singleDndUpdate && ui.sender !== null) {
95      var senderSerialize = $.jalios.Sortable.serialize(ui.sender, $(ui.sender).hasClass('dnd-container') ? 'dnd-sortable-sender' : 'sortable-sender');
96      serialize = $.extend(serialize, senderSerialize);
97    }
98    
99    event.currentTarget = that;
100    $.jalios.DataBroker.trigger($that, event, { 
101      params : serialize
102    });
103    
104  }
105  
106  // ------------------------------------------
107  //  PUBLIC
108  // ------------------------------------------
109  
110  // Namespace
111  if (!$.jalios) { $.jalios = {}; }
112  
113  /**
114   * Provides mechanisms to handle sortable (drag and drop) of list's items and container's boxes using jQueryUI Sortable Widget.
115   * <br/><br/>
116   * 
117   * <h5>List</h5>
118   * List with classes <code>UL.sortable</code> and <code>OL.sortable</code> will trigger this feature.
119   * <ul>
120   *   <li><code>.sortable-x</code> constraint horizontal drag</li>
121   *   <li><code>.sortable-y</code> constraint vertical drag</li>
122   *   <li><code>.sortable-handle</code> define drag handle and must be on sortable</li>
123   *   <li><code>.sortable-disable</code> element to bypass</li>
124   * </ul>
125   * 
126   * Attribute <code>data-jalios-sortable-connect</code> define the sortable to connect with
127   * 
128   * <h5>Boxes</h5>
129   * DIV with classes <code>DIV.dnd-container</code> will trigger this feature.
130   * <ul>
131   *   <li><code>.dnd-horizontal</code> constraint horizontal drag</li>
132   *   <li><code>
132.dnd-vertical</code> constraint vertical drag</li>
133   *   <li><code>.dnd-single</code> prevent a connection with other dnd-container</li>
134   *   <li><code>.dnd-single-update</code> will trigger only one jalios:sortable event and databroker event for all connection with other dnd-container</li>
135   *   <li><code>.dnd-debug</code> will print update event in browser console</li> 
136   *   <li><code>.dnd-noresponse</code> for portal ajax refresh, the DOM will not be refresh with the response.</li>
137   * </ul>
138   * 
139   * <h5>Events</h5>
140   * An event <code>jalios:sortable</code> is trigged when a drop has been performed.
141   * <ul>
142   *   <li>sortable.container: the container element (dnd-sortable forboxes)</li>
143   *   <li>sortable.ui: the jQuery sortable ui event</code></li>
144   * </ul>
145   * 
146   * A broker event is also performed to trigger listeners: ajax-refresh, modal, ...<br/>
147   * 
148   * The options's param is filled with the serialised content  
149   * 
150   * <h5>FIXME</h5>
151   * <ul>
152   *   <li>Handle connectWith on list</li>
153   *   <li>Handle nested list</li>
154   * </ul>
155   * 
156   * @namespace $.jalios.Sortable
157   * @copyright Jalios SA
158   * @see $.jalios.DataBroker
159   * @see $.jalios.AjaxRefresh
160   * 
161   * @example
162   * 
163   * Drop will trigger action ajax-refresh on UL with parameters: key=HelloA&key=HelloB&key=HelloC&key=HelloD&sortable=key
164   * 
165   * &lt;ul id="key" class='sortable' data-jalios-action="ajax-refresh"&gt;
166   *   &lt;li data-value="HelloA"&gt;&lt;a href='#'&gt;Hello World 1&lt;/a&gt;&lt;/li&gt;
167   *   &lt;li id="HelloB"&gt;&lt;a href='#'&gt;Hello World 2&lt;/a&gt; Yep&lt;/li&gt;
168   *   &lt;li data-value="HelloC"&gt;&lt;a href='#'&gt;Hello World 3&lt;/a&gt;&lt;/li&gt;
169   *   &lt;li data-value="HelloD"&gt;&lt;a href='#'&gt;Hello World 4&lt;/a&gt;&lt;/li&gt;
170   * &lt;/ul&gt;
171   * 
172   * @example
173   * 
174   * Drop on first column will trigger an ajax-refresh on dnd-container with parameters: bind1=c_1234&bind1=c_1234&bind1=c_1234&sortable=bind1.
175   * 
176   * This behavior simplifed by jalios-sortable-portal.js (data-jalios-action attribute is not required). PortletCollection includes doAjaxHandleSortable.jsp to updates portlet bindings 
177   * 
178   * &lt;jalios:buffer name="box"&gt;
179   *   &lt;div class='box ID_c_1234'&gt;
180   *     &lt;div class="box-header dnd-handle"&gt;&lt;h3&gt;Box title&lt;/h3&gt;&lt;/div&gt;
181   *     &lt;div class="box-body"&gt;Box body&lt;/div&gt;
182   *     &lt;div class="box-footer"&gt;Box footer&lt;/a&gt;&lt;/div&gt;
183   *   &lt;/div&gt;
184   * &lt;/jalios:buffer&gt;
185   * 
186   * &lt;div class='row-fluid'&gt;
187   *   &lt;div id="bind1" class='span4 dnd-container'&gt;
188   *     &lt;%= box %&gt; &lt;%= box %&gt; &lt;%= box %&gt;
189   *   &lt;/div&gt;
190   *   &lt;div id="bind2" class='span4 dnd-container'&gt;
191   *     &lt;%= box %&gt; &lt;%= box %&gt; &lt;%= box %&gt;
192   *   &lt;/div&gt;
193   *   &lt;div id="bind3" class='span4 dnd-container'&gt;
194   *     &lt;%= box %&gt; &lt;%= box %&gt; &lt;%= box %&gt;
195   *   &lt;/div&gt;
196   * &lt;/div&gt;
197   * 
198   */ 
199  
200  $.jalios.Sortable = {
201  
202   /**
203    * Serialize a given sortable with serialized children.<br/>
204    * Do not use defaut serialisation because of JcmsID and other custom behavior.
205    * 
206    * @param container the selector of the container
207    * @param key optionnal parameter key to be used to send the container id
208    * @return a JSON object representation
209    */
210    serialize: function(container, key){
211
212      var key = key || 'sortable';
213      
214      // Perform selector
215      var $container = $(container);
216      
217      // Serialize sortable items
218      var serial = $container.children().map(function() {  // FIXME: should escape some children
219        var $this  = $(this);
220        
221        // Retrive data-value ou JcmsId
222        var value = $this.attr('data-value') || $this.getJcmsId();
223        if (value){ return value; }
224        
225        // look into first child (Handle wrappers grid)
226         var $child = $this.children(':first');
227         value = $child.attr('data-value') || $child.getJcmsId();
228         if (value){ return value; }
229        
230        // At last use ID
231        return $this.attr('id'); 
232      }).get();
233      
234      // Build sortable key
235      var sortable = $.jalios.Sortable.getSortableKey($container);
236      
237      // Build params
238      var params = {};
239
240      var additionnalParams = $container.attr('data-sortable-params');
241      try {
242        params = $.extend(params, additionnalParams && JSON.parse( additionnalParams ));
243      } catch ( error ) {
244        jQuery.console.error('Error parsing data-sortable-params on ', $container, error );
245      }
246      
247      params[key || 'sortable'] = sortable;
248      params[sortable] = serial;
249      
250      // Returns the serialized representation
251      return params;
252    },
253    
254    getSortableKey: function($sortable){
255      return $sortable.attr('data-value') || $sortable.attr('id') || $sortable.getJcmsId() || 'sortitem';
256    },
257    
258    /**
259     * Build a sortable for the given element using css declaration of list (sortable-*).<br/> 
260     * Used by sortable-widget.js to lazy kickstart sortable on focusin.
261     * 
262     * @param element the element to work with
263     * 
264     */
265    buildSortable: function(element, options){
266      var $e = $(element);
267      var options = options || {};
268      $e.sortable({
269        'items':       options.items  || '> LI', // Only LI
270        'cancel':      options.cancel || '.sortable-disable, :input',
271        'axis':        options.axis   || ($e.hasClass('sortable-x') ? 'x' : $e.hasClass('sortable-y') ? 'y' : false),
272        'revert' :     options.revert || true,
273        'handle':      options.handle || ($e.hasClass('sortable-handle') ? '.sortable-handle' : false),
274        'connectWith': options.connectWith || false,
275        'tolerance':   options.tolerance   || 'intersect',
276        'placeholder': options.placeholder,
277        'update': function(evt, ui){ trigger(this, ui);  },
278        'stop':   function(evt, ui){ hover(this, false); },
279        'sort':   function(evt, ui){ hover(this, true);  },
280        'out':    function(evt, ui){ hover(this, false); }, 
281        'over':   function(evt, ui){ hover(this, true);  }
282      });
283    }
284  }
285  
286  // ------------------------------------------
287  //  FUNCTION
288  // ------------------------------------------
289  
290  $.fn.sortable = $.fn.sortable || {};
291  
292  $.fn.sortable.add = function(value){
293    var $elm = $(value);
294    if (!$elm.exists()){
295      var tag = $(this).hasClass('sortable') ? 'li' : 'div';
296      $elm = $('<'+tag+' data-value="'+value+'"></'+tag+'>');
297    }
298    
299    return this.each(function() {
300      $(this).append($elm);
301      trigger(this);
302    });
303  }
304  
305  $.fn.sortable.remove = function(elm){
306    $(elm).remove();
307    return this.each(function() {
308      trigger(this);
309    });
310  }
311  
312  // ------------------------------------------
313  //  DOM Ready
314  // ------------------------------------------
315
316
317  // Plugin initialization on DOM ready
318  $(document).ready(function($) {
319    register();
320  });
321  
322}(window.jQuery);
323
324
325  // ------------------------------------------
326  //  DEPRECATED
327  // ------------------------------------------
328
329  var Sortable = {};
330  Sortable.create = function(){
331    jQuery.console.warn("[Deprecated] JCMS requires the new Sortable framework");
332    jQuery.console.stacktrace();
333  }
334  Sortable.destroy = function(){
335    jQuery.console.warn("[Deprecated] JCMS requires the new Sortable framework");
336    jQuery.console.stacktrace();
337  }
338  
339  var Droppables = {};
340  Droppables.add = function(){
341    jQuery.console.warn("[Deprecated] JCMS requires the new Sortable framework");
342    jQuery.console.stacktrace();
343  }
344  
345  var PortalSortable = {};
346  PortalSortable.create = function(){
347    jQuery.console.warn("[Deprecated] JCMS requires the new Sortable framework");
348    jQuery.console.stacktrace();
349  }

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.