source: extensions/GrumPluginClasses/js/criteriaBuilder.js @ 7175

Last change on this file since 7175 was 7175, checked in by grum, 14 years ago

Packing js files + add categorySelector functionnalities

File size: 15.8 KB
Line 
1/**
2 * -----------------------------------------------------------------------------
3 * file: criteriaBuilder.js
4 * file version: 1.0.0
5 * date: 2010-05-01
6 *
7 * JS file provided by the piwigo's plugin "GrumPluginClasses"
8 *
9 * -----------------------------------------------------------------------------
10 * Author     : Grum
11 *   email    : grum@piwigo.com
12 *   website  : http://photos.grum.fr
13 *   PWG user : http://forum.phpwebgallery.net/profile.php?id=3706
14 *
15 *   << May the Little SpaceFrog be with you ! >>
16 * -----------------------------------------------------------------------------
17 *
18 * -----------------------------------------------------------------------------
19 * This plugin use the Nested Sortable Plugin / version 1.0.1
20 *    Copyright (c) 2007 Bernardo de Padua dos Santos
21 *    Dual licensed under the MIT (MIT-LICENSE.txt)
22 *    and GPL (GPL-LICENSE.txt) licenses.
23 *
24 *    http://code.google.com/p/nestedsortables/
25 * -----------------------------------------------------------------------------
26 *
27 * an object dedicaded for Piwigo, giving easy user methods to make complex
28 * requests
29 *
30 * constructor : myCB = new criteriaBuilder(containerId [, options]);
31 *
32 *  - containerId : the Id of the DOM element where the criteria will be added
33 *  - options : an object with this properties :
34 *       . textAND       : String, with default value = 'AND'
35 *                         displayed text to indicates the type of operator AND
36 *       . textOR        : String, with default value = 'OR',
37 *                         displayed text to indicates the type of operator OR
38 *       . textHint      : String, with default value = '',
39 *       . classGroup    : String, with default value = '',
40 *       . classItem     : String, with default value = '',
41 *       . classOperator : String, with default value = '',
42 *       . classHelper   : String, with default value = 'helper',
43 *       . opacity       : String, with default value = 0.8,
44 *       . onEdit        : handler on a function to manage click on the 'Edit'
45 *                         button ; event.data contain the item Id
46 *       . onDelete      : handler on a function to manage click on the 'Delete'
47 *                         button ; event.data contain the item Id
48 *       . imgEditUrl    : String, with default value = '',
49 *       . imgDeleteUrl  : String, with default value = '',
50 *
51 *
52 *
53 * :: HISTORY ::
54 *
55 * | release | date       |
56 * | 1.0.0   | 2010/04/27 | start to coding
57 * |         |            |
58 * |         |            |
59 * |         |            |
60 * |         |            |
61 * |         |            |
62 * |         |            |
63 *
64 */
65
66
67
68function criteriaBuilder(container)
69{
70  var itemsId = {
71          group:'iCbGroup',
72          item:'iCbItem',
73          container:container,
74        },
75      counters = {
76          group:0,
77          item:0,
78        },
79      options = {
80          textAND:'AND',
81          textOR:'OR',
82          textHint:'',
83          classGroup:'',
84          classItem:'',
85          classOperator:'',
86          classHelper:'helper',
87          opacity:0.8,
88          onEdit:null,
89          onDelete:null,
90          onRequestSuccess:null,
91          onRequestError:null,
92          onGetPageSuccess:null,
93          onGetPageError:null,
94          imgEditUrl:'',
95          imgDeleteUrl:'',
96          ajaxUrl:'',
97        },
98      extraData = new Array();
99
100  if(arguments.length==2)
101  {
102    if(typeof arguments[1]=='object')
103    {
104      options = jQuery.extend(options, arguments[1]);
105    }
106  }
107
108  /**
109   *
110   *
111   */
112  this.doAction = function (fct)
113  {
114    switch(fct)
115    {
116      case 'add':
117        /* function 'add' : adding an item
118         * the second parameter is the item content
119         * the third parameter is extra data associated with item
120         */
121        if(arguments.length==3)
122        {
123          if(typeof arguments[1]=='string')
124          {
125            addItem(arguments[1], arguments[2]);
126          }
127        }
128        break;
129      case 'delete':
130        /* function 'delete' : remove an item
131         * the second parameter is the item ID
132         */
133        if(arguments.length==2)
134        {
135          if(typeof arguments[1]=='string')
136          {
137            deleteItem(arguments[1]);
138          }
139        }
140        break;
141
142      case 'edit':
143        /* function 'edit' : edit an item content
144         * the second parameter is the item ID
145         * the third parameter is the new content
146         * the fourth parameter is the new extra data associated with item
147         */
148        if(arguments.length==4)
149        {
150          if(typeof arguments[1]=='string' && typeof arguments[2]=='string' )
151          {
152            editItem(arguments[1], arguments[2], arguments[3]);
153          }
154        }
155        break;
156
157      case 'get':
158        /* function 'get' : returns extra data associated with item, ready to be
159         * used
160         */
161        return(getItems());
162        break;
163
164      case 'getExtraData':
165        /* function 'getExtraData' : returns extra data associated with item in
166         * native format
167         */
168        if(arguments.length==2)
169        {
170          return(getExtraData(arguments[1]));
171        }
172        else
173        {
174          return(null);
175        }
176        break;
177
178      case 'clear':
179        /* function 'clear' : clear all criteria
180         */
181        clearItems();
182        break;
183
184      case 'send':
185        /* function 'send' : send request to the server
186         */
187        sendRequest();
188        break;
189
190      case 'getPage':
191        /* function 'send' : send request to the server
192         * the second parameter is the request number
193         * the third parameter is the page number
194         * the fourth parameter is the number of ityem per page
195         */
196        if(arguments.length==4)
197        {
198          getPage(arguments[1], arguments[2], arguments[3]);
199        }
200        break;
201
202      case 'setOptions':
203        /* function 'setOptions' : allows to set options after the object was
204         * created
205         */
206        if(arguments.length==2)
207        {
208          return(setOptions(arguments[1]));
209        }
210        break;
211    }
212  };
213
214  /**
215   * wrap an item in a new group
216   *
217   * !it's considered that the current item parent is the criteria builder area!
218   *
219   * @param String item : ID of the item to be wrapped
220   */
221  var addGroup = function (itemId)
222  {
223    counters.group++;
224
225    var content="<li id='"+itemsId.group+counters.group+"' class='cbGroup cbSortable cbOpAND "+options.classGroup+"'>";
226    content+="<ul></ul></li>";
227
228    $('#'+itemId).wrap(content);
229
230    content="<div class='cbSortHandle'>";
231    content+="<div id='"+itemsId.group+counters.group+"OpAND' class='"+options.classOperator+"' style='display:none;'>"+options.textAND+"</div>";
232
233    content+="<div id='"+itemsId.group+counters.group+"OpOR' class='"+options.classOperator+"' style='display:none;'>"+options.textOR+"</div>";
234    content+="</div>";
235
236    $("#"+itemsId.group+counters.group).prepend(content);
237
238    $('#'+itemsId.group+counters.group+'OpAND').bind('click', itemsId.group+counters.group, onSwitchOperator);
239    $('#'+itemsId.group+counters.group+'OpOR').bind('click', itemsId.group+counters.group, onSwitchOperator);
240
241    applyNested();
242  };
243
244  /**
245   * remove a group
246   *
247   * @param String groupId : ID of the group
248   */
249  var removeGroup = function (groupId)
250  {
251    $('#'+groupId).remove();
252  };
253
254  /**
255   * add a new item in the criteria builder area
256   *
257   * @param String content : content of the new item
258   */
259  var addItem = function (itemContent, data)
260  {
261    counters.item++;
262
263    var content="<li id='"+itemsId.item+counters.item+"' class='cbItem cbSortable "+options.classItem+"'>";
264    content+="<div class='cbItemButtons' style='float:right;'>";
265
266    if(options.imgEditUrl!='' &&
267       options.onEdit!=null &&
268       jQuery.isFunction(options.onEdit)) content+="<img id='iImgEdit"+counters.item+"' src='"+options.imgEditUrl+"'/>";
269
270    if(options.imgDeleteUrl!='' &&
271       options.onDelete!=null &&
272       jQuery.isFunction(options.onDelete)) content+="<img id='iImgDelete"+counters.item+"' src='"+options.imgDeleteUrl+"'/>";
273
274    content+="</div><div class='cbSortHandle'>"+itemContent+"</div></li>";
275
276    $('#'+itemsId.container).append(content);
277
278    addGroup(itemsId.item+counters.item);
279
280    if(options.imgEditUrl!='' && options.onEdit!=null)
281    {
282      $('#iImgEdit'+counters.item).bind('click', itemsId.item+counters.item, options.onEdit);
283    }
284
285    if(options.imgDeleteUrl!='' && options.onDelete!=null)
286    {
287      $('#iImgDelete'+counters.item).bind('click', itemsId.item+counters.item, options.onDelete);
288    }
289
290    extraData[counters.item]=data;
291  };
292
293  /**
294   * remove an item from the criteria builder area and do a check to determine
295   * if parent group have to be removed
296   *
297   * @param String itemId : ID of the item to remove
298   */
299  var deleteItem = function (itemId)
300  {
301    if($('#'+itemId).length!=0)
302    {
303      $('#'+itemId).remove();
304      re=/[0-9]*$/;
305      extraData[eval(re.exec(itemId)[0])]=null;
306      manage();
307    }
308  };
309
310  /**
311   * modify the content of an item
312   *
313   * if set, trigger the 'onEdit' function after the item was modified
314   *
315   * @param String itemId : ID of the item to modify
316   * @param String content : the new content to be applied
317   */
318  var editItem = function (itemId, content, data)
319  {
320    if($('#'+itemId).length!=0)
321    {
322      $('#'+itemId+' .cbSortHandle').html(content);
323      re=/[0-9]*$/;
324      extraData[eval(re.exec(itemId)[0])]=data;
325    }
326  };
327
328  /**
329   * clear all the criteria
330   */
331  var clearItems = function()
332  {
333    $('#'+itemsId.container).NestedSortableDestroy();
334    $('#'+itemsId.container).html("");
335    counters.item=0;
336    counters.group=0;
337    extraData=new Array();
338  };
339
340  /**
341   * used by the getItems to serialize extraData objects
342   *
343   * @param String prefix : the prefix name for variable in the serialized string
344   * @param value : the value of the variable
345   * @return String : the serialized object
346   */
347  var serializeData=function(prefix, value)
348  {
349    returned='';
350    if(typeof value =='object')
351    {
352      for(var key in value )
353      {
354        if(typeof value[key] =='object')
355        {
356          returned+=serializeData(prefix+'['+key+']', value[key]);
357        }
358        else
359        {
360          returned+='&'+prefix+'['+key+']='+value[key];
361        }
362      }
363    }
364    else
365    {
366      returned+='&'+prefix+'='+value;
367    }
368    return(returned);
369  };
370
371
372  /**
373   *
374   * @return String : items in a string ready to use in an url
375   */
376  var getItems = function()
377  {
378    //group & items tree
379    serialized=jQuery.iNestedSortable.serialize(itemsId.container)['hash'];
380
381    //items extraData
382    tmp=Array();
383    for(i=0;i<extraData.length;i++)
384    {
385      if(extraData[i]!=null)
386      {
387        serialized+=serializeData('extraData['+i+']', extraData[i]);
388      }
389    }
390
391    //group Operators
392    $('#'+itemsId.container+' .cbGroup').each(
393      function ()
394      {
395        re=/[0-9]*$/;
396        serialized+='&operator['+re.exec(this.id)[0]+']=';
397        if($(this).hasClass('cbOpOR'))
398        {
399          serialized+='OR';
400        }
401        else
402        {
403          serialized+='AND';
404        }
405      }
406    );
407
408    return(serialized);
409  };
410
411
412  /**
413   *
414   * @return : return extradata (in native format) associated with item
415   */
416  var getExtraData = function(itemId)
417  {
418    re=/[0-9]*$/;
419    extraDataNumber=re.exec(itemId)[0];
420
421    return(extraData[extraDataNumber]);
422  };
423
424
425  /**
426   *
427   * @param Object options : set the given option
428   */
429  var setOptions = function(optionsToSet)
430  {
431    options = jQuery.extend(options, optionsToSet);
432  };
433
434  /**
435   * display/hide operator title for a group
436   *
437   * @param String groupId : ID of the group
438   * @param Boolean visible : set true to display the title, false to hide it
439   */
440  var displayOperator = function (groupId, visible)
441  {
442    if($('#'+groupId).hasClass('cbOpAND'))
443    {
444      if(visible)
445      {
446        $('#'+groupId+'OpAND').css('display', 'block');
447      }
448      else
449      {
450        $('#'+groupId+'OpAND').css('display', 'none');
451      }
452    }
453    else
454    {
455      if(visible)
456      {
457        $('#'+groupId+'OpOR').css('display', 'block');
458      }
459      else
460      {
461        $('#'+groupId+'OpOR').css('display', 'none');
462      }
463    }
464  };
465
466  /**
467   * manage the criteria builder groups&items
468   *
469   * check validity for a group : an empty group is removed
470   * check validity for an item : for an item directly attached to the criteria
471   *                              builder area is wrapped in a new group
472   */
473  var manage = function ()
474  {
475    $('#'+itemsId.container+' li').each(
476      function()
477      {
478        if($(this).hasClass('cbGroup'))
479        {
480          if($('#'+this.id+' li.cbItem').length==0)
481          {
482            // a group without item is removed
483            removeGroup(this.id);
484          }
485          else if($('#'+this.id+' li.cbItem').length==1)
486          {
487            displayOperator(this.id, false);
488          }
489          else
490          {
491            displayOperator(this.id, true);
492          }
493        }
494        else if($(this).hasClass('cbItem'))
495        {
496          if($(this).parent().get(0).id==itemsId.container)
497          {
498            // an item without group as parent is wrapped in a new group
499            addGroup(this.id);
500          }
501        }
502      }
503    );
504  };
505
506  /**
507   * this function make the groups&items ready to be sorted & grouped
508   */
509  var applyNested = function ()
510  {
511   // $.data($('#'+itemsId.container)[0], 'id', this);
512    $('#'+itemsId.container).NestedSortableDestroy();
513    $('#'+itemsId.container).NestedSortable(
514      {
515        accept: 'cbSortable',
516        noNestingClass: 'cbItem',
517        opacity: options.opacity,
518        helperclass: options.classHelper,
519        serializeRegExp:/.*/i,
520        autoScroll: true,
521        handle: '.cbSortHandle',
522        ghosting:false,
523        nestingPxSpace:15,
524
525        onChange: function(serialized) {
526          manage();
527        },
528      }
529    );
530  };
531
532  /**
533   * switch the operator for a group
534   *
535   * event.data = ID of the group
536   */
537  onSwitchOperator = function (event)
538  {
539    groupId=event.data;
540
541    if($('#'+groupId).hasClass('cbOpAND'))
542    {
543      $('#'+groupId).removeClass('cbOpAND').addClass('cbOpOR');
544      $('#'+groupId+'OpAND').css('display', 'none');
545      $('#'+groupId+'OpOR').css('display', 'block');
546    }
547    else
548    {
549      $('#'+groupId).removeClass('cbOpOR').addClass('cbOpAND');
550      $('#'+groupId+'OpAND').css('display', 'block');
551      $('#'+groupId+'OpOR').css('display', 'none');
552    }
553  };
554
555  /**
556   *
557   *
558   */
559  var sendRequest = function()
560  {
561    datas=encodeURI('requestName='+itemsId.container+'&'+getItems());
562    $.ajax(
563      {
564        type: "POST",
565        url: options.ajaxUrl+'execute',
566        async: true,
567        data: datas,
568        success: function(msg)
569          {
570            if(options.onRequestSuccess!=null && jQuery.isFunction(options.onRequestSuccess)) options.onRequestSuccess(msg);
571          },
572        error: function(msg)
573          {
574            if(options.onRequestError!=null && jQuery.isFunction(options.onRequestError)) options.onRequestError(msg);
575          },
576       }
577     );
578
579  };
580
581  /**
582   *
583   *
584   */
585  var getPage = function(requestNumber, pageNumber, numberPerPage)
586  {
587    datas=encodeURI('requestName='+itemsId.container+'&'+getItems());
588    $.ajax(
589      {
590        type: "POST",
591        url: options.ajaxUrl+'getPage',
592        async: true,
593        data: {page:pageNumber, requestNumber:requestNumber, numPerPage:numberPerPage},
594        success: function(msg)
595          {
596            if(options.onGetPageSuccess!=null && jQuery.isFunction(options.onGetPageSuccess)) options.onGetPageSuccess(msg);
597          },
598        error: function(msg)
599          {
600            if(options.onGetPageError!=null && jQuery.isFunction(options.onGetPageError)) options.onGetPageError(msg);
601          },
602       }
603     );
604
605  };
606
607  applyNested();
608};
609
610
611criteriaBuilder.makeExtendedData = function(owner, data)
612{
613  return(
614    {
615      owner:owner,
616      param:data,
617    }
618  );
619}
Note: See TracBrowser for help on using the repository browser.