source: extensions/GrumPluginClasses/js/rbCriteriaBuilder.js @ 16012

Last change on this file since 16012 was 16012, checked in by grum, 12 years ago

feature:2634- compatibility with Piwigo 2.4
+add some objects on js framework

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