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

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

some file forgotten in the previous commit...

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