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

Last change on this file since 7310 was 7310, checked in by grum, 13 years ago

fix bug on the rbuilder and migrate ajax call on the gpc ajax manager
fix bug:1945
add some functionnalities

File size: 15.8 KB
Line 
1/**
2 * -----------------------------------------------------------------------------
3 * file: criteriaBuilder.js
4 * file version: 1.1.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 * | 1.1.0   | 2010/10/20 | * change ajax methods
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('ajaxfct=admin.rbuilder.searchExecute&requestName='+itemsId.container+'&'+getItems());
562    $.ajax(
563      {
564        type: "POST",
565        url: options.ajaxUrl,
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    $.ajax(
588      {
589        type: "POST",
590        url: options.ajaxUrl,
591        async: true,
592        data: {ajaxfct:'admin.rbuilder.searchGetPage', page:pageNumber, requestNumber:requestNumber, numPerPage:numberPerPage},
593        success: function(msg)
594          {
595            if(options.onGetPageSuccess!=null && jQuery.isFunction(options.onGetPageSuccess)) options.onGetPageSuccess(msg);
596          },
597        error: function(msg)
598          {
599            if(options.onGetPageError!=null && jQuery.isFunction(options.onGetPageError)) options.onGetPageError(msg);
600          },
601       }
602     );
603
604  };
605
606  applyNested();
607};
608
609
610criteriaBuilder.makeExtendedData = function(owner, data)
611{
612  return(
613    {
614      owner:owner,
615      param:data,
616    }
617  );
618}
Note: See TracBrowser for help on using the repository browser.