PageSourceSearch

https://kulturportal.de/module/jscript/lib/cb_ui/widget.js

js kulturportal.de collected 2026-09-24 22:22:49 UTC 16,368 bytes, 545 lines download raw bytes

1/* This file is part of cbui.
2 * Copyright © 2010-2012 stiftung kulturserver.de ggmbh <[email protected]>
3 *
4 * cbui is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * cbui is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with cbui.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/**
19 * A widget toolkit for culturebase. A widget is a simle GUI element with some
20 * functionality and an internal state. Widgets are
21 * - extendable: If you need a widget similar to one we already have you can
22 *    subclass the existing one. Always keep this in mind when you do, though.
23 * - reusable: Widgets are to be collected in a central place and are thus
24 *    available to all CB applications and web sites.
25 * - translatable: Widgets integrate with cb-ml.
26 * - managable: Widgets have a life cycle. You can create and destroy them and
27 *    they will behave nicely when you do. Widgets can be composed into windows
28 *    which will take away much of the management burden.
29 * - validatable: Certain widgets can accomodate subclassses of
30 *    CbValidate.validator and provide validate() methods.
31 *
32 * In order for this to work you need to include:
33 * - jquery.js
34 * - base2.js
35 * - cb_ui/validate.js (if there are any widgets to be validated)
36 * - some styles for '__CbUi*'
37 *
38 */
39
40/**
41 * The widget registry collects information about all available widget classes
42 * and manages translation, instantiation and destruction of widgets.
43 *
44 */
45jQuery.CbWidgetRegistry = jQuery.CbWidgetRegistry || {
46   /**
47    * get a widget or validator name from a class name
48    */
49   translateToClass : function(name, prefix) {
50      return '.__Cb' + prefix + name.substring(0, 1).toUpperCase() + name.substring(1);
51   },
52
53   /* some properties you can change to modify the behaviour of the widget registry */
54
55   /**
56    * The projects to be queried for ML bricks.
57    */
58   projects : ['cb-framework'],
59
60   /** old API for querying bricks; deprecated */
61   project : '',
62   baseProject : '',
63
64   /**
65    * language to be used
66    */
67   language : 'en_EN',
68
69   brickSource : "/module/lib/framework/getMlBricks.php",
70
71   /**
72    * The actual translated bricks. Be careful when modifying this.
73    */
74   bricks : {},
75
76   /**
77    * Create a proper projects array from this.project and this.baseProject if
78    * they're given.
79    */
80   retrofitProjects : function() {
81      var projects = [];
82      if (this.project) projects.push(this.project);
83      if (this.baseProject) projects.push(this.baseProject);
84      if (projects.length > 0) {
85         this.projects = projects
86         this.project = '';
87         this.baseProject = '';
88      }
89   },
90
91   /**
92    * change the language of all widgets in the given context
93    * @param language the new language (locale)
94    * @param context the context to be manipulated - for example a window
95    * @param callback Function to be called when done
96    */
97   changeLanguage : function(language, context, callback) {
98      var labels = [];
99      this.language = language;
100      if (!this.language) {
101         if (callback !== undefined) callback();
102         return; // translation disabled
103      }
104      var self = this;
105      try {
106         /* collect labels */
107         jQuery.each(jQuery.CbWidget, function(name) {
108            var clazz = self.translateToClass(name, 'Ui');
109            jQuery(clazz, context).each(function() {
110               jQuery.merge(labels, jQuery(this).CbWidget().getLabels());
111            });
112            if (context && context.is(clazz)) {
113               jQuery.merge(labels, jQuery(context).CbWidget().getLabels());
114            }
115            labels = jQuery.unique(labels);
116         });
117      }catch(e){
118         if(console) console.log(e);
119      }
120
121
122      if (labels.length === 0) {
123         if (callback !== undefined) callback();
124         return; // no translation needed
125      }
126
127      /* for backward compatibility */
128      this.retrofitProjects();
129
130      /* fetch bricks */
131      jQuery.ajax({
132         type : 'GET',
133         url : this.brickSource,
134         dataType : 'json',
135         data : {
136            "projects" : this.projects,
137            "language" : this.language,
138            "labels[]" : labels
139         },
140         success : function(bricks) {
141            /* loop over widgets again and apply bricks */
142            self.bricks = bricks;
143            jQuery.each(jQuery.CbWidget, function(name) {
144                var clazz = self.translateToClass(name, 'Ui');
145                jQuery(clazz, context).each(function() {
146                   //if (jQuery(this).CbWidget())
147                     jQuery(this).CbWidget().changeLanguage(bricks);
148                });
149                if (context && context.is(clazz)) {
150                     jQuery(context).CbWidget().changeLanguage(bricks);
151                }
152            });
153            if (callback !== undefined) callback();
154         }
155     });
156   },
157
158   /**
159    * Instantiate widgets and validators in the given context and translate them.
160    * @param context A DOM element to restrict the operation to (e.g. a window)
161    * @param callback Function to be called when done
162    */
163   apply : function(context, callback) {
164      var self = this;
165
166      /* create widgets */
167      jQuery.each(jQuery.CbWidget, function(name, widget) {
168         jQuery(self.translateToClass(name, 'Ui'), context).each(function() {
169            var el = jQuery(this);
170            if (el.CbWidget(undefined, false) === undefined) { // but don't overwrite existing ones
171               new widget(el);
172            }
173         });
174      });
175
176      jQuery.each(jQuery.CbValidate, function(name, validator) {
177         jQuery(self.translateToClass(name, 'Validate'), context).each(function() {
178            new validator(jQuery(this).CbWidget());
179         });
180      });
181
182      this.changeLanguage(this.language, context, callback);
183   }
184};
185
186/**
187 * Event Handling
188 * --------------
189 *
190 * Events are declared by implementing an "init" method in the class interface
191 * of your widget and stating "jQuery.CbEvent(this, <name>)" there. There are
192 * two ways of triggering the event:
193 *
194 * 1. Call widget.<name>() without parameters. This is the shortcut for events
195 * you don't want to specify any special parameters for.
196 *
197 * 2. Call widget.trigger(<name>, <parameters>) where <parameters> are a JS
198 * object. The parameters will be passed on to the event handlers then.
199 *
200 * Event handlers can be attached to events in three ways.
201 *
202 * 1. Override handle<Name>(). This method is the first to be called every time
203 * the event is triggered. You can use base2's inheritance mechanism here and
204 * call base() to invoke the handle<Name>() method of super classes.
205 *
206 * 2. Call widget.<name>(<handler>, <params>). <handler> should be a function to be
207 * executed when the event is triggered. Like this you can attach multiple handlers
208 * to the same event in jquery-style. They will be invoked after handle<Name>().
209 * Any parameters will be passed on to all event handlers when they are invoked.
210 * You can extend and override them with trigger().
211 *
212 * 3. Call widget.bind(<name>, <handler>, <params>). This is the same as
213 * widget.<name>(<handler>, <params>).
214 *
215 * You can unbind handlers from an event by calling widget.unbind(<event>, <handler>).
216 * If you omit the second parameter all handlers will be unbound from the specified
217 * event.
218 *
219 * (Class interfaces aren't inherited in base2 so we have to create an external
220 * CbEvent function to add events to classes.)
221 *
222 */
223jQuery.CbEvent = jQuery.CbEvent || function(target, name) {
224   jQuery.CbEvent.getHandleName = function(name) {
225      return "handle" + name.substring(0,1).toUpperCase() + name.substring(1);
226   };
227
228   var event = {};
229   event[name] = function(callback, staticParams) {
230      if (callback) {
231         if (typeof(this.handlers[name]) == 'undefined') this.handlers[name] = [];
232         this.handlers[name].push({
233            'callback' : callback,
234            'params': staticParams || {}
235         });
236      } else {
237         this.trigger(name);
238      }
239   };
240
241   var handleName = jQuery.CbEvent.getHandleName(name);
242   if (typeof(target.prototype[handleName]) == 'undefined') {
243      event[handleName] = function() {return this;};
244   }
245
246   target.implement(event);
247   return target[name];
248};
249
250jQuery.CbWidget = jQuery.CbWidget || function() {}; // maybe do something useful here; e.g. find elements belonging to certain widget types
251jQuery.CbValidate = jQuery.CbValidate || function() {};
252
253/**
254 * jquery plugin to enable $(element).CbWidget() functionality. Saves information
255 * about widgets via $.data(...).
256 * @param widget if set attach the widget to the element otherwise find the
257 *    widget belonging to the element. If set to null remove widget information
258 *    from the element.
259 *    When querying for the widget CbWidget will recursively search the elements
260 *    parent nodes.
261 * @param recursive If the widget should be looked for recursively up the DOM
262 *    tree. If undefined, true is assumed.
263 */
264jQuery.fn.CbWidget = function(widget, recursive) {
265   if (recursive === undefined) recursive = true;
266   if (this.length == 0) return undefined;
267   if (widget !== undefined) {
268      if (widget !== null) {
269         this.data("cb_widget", widget);
270      } else {
271         this.removeData("cb_widget");
272      }
273   }
274
275   if (!this.data("cb_widget")) {
276      var parent = this.parent();
277      if (recursive && parent && parent != this) {
278         return parent.CbWidget();
279      } else {
280         return undefined;
281      }
282   } else {
283      return this.data("cb_widget");
284   }
285};
286
287/**
288 * the base widget. All widgets are to be subclassed from this one.
289 */
290jQuery.CbWidget.widget = base2.Base.extend({
291
292   /**
293    * create a widget on the given element.
294    * @param element the element the widget should attach to
295    */
296   constructor : function(element) {
297      this.base();
298      base2.assignID(this);
299      this.parentElement = element;
300      this.element().CbWidget(this);
301      /* element() and parentElement may differ */
302      this.parentElement.CbWidget(this);
303
304      /**
305       * association of positions -> labels
306       */
307      this.texts = {};
308
309      /**
310       * event handlers
311       */
312      this.handlers = {};
313      
314      this.validationSuspended = false;
315   },
316
317   /**
318    * show the widget
319    */
320   handleShow : function() {
321      this.element().show();
322      return this;
323   },
324
325   /**
326    * hide the widget
327    */
328   handleHide : function() {
329      this.element().hide();
330      return this;
331   },
332
333   /**
334    * get the element the widget belongs to. Some widgets might override this
335    * method and/or change their element. Don't assume the element to be the
336    * same every time you use it.
337    */
338   element : function() {
339      return this.parentElement;
340   },
341
342   /**
343    * Refresh the element associated with this widget. This is necessary if it
344    * has been inserted or moved in the DOM. You will want to rebind all events
345    * here.
346    */
347   refreshElement : function() {
348      this.parentElement = jQuery(this.parentElement);
349      this.element().CbWidget(this);
350   },
351
352   /**
353    * get labels for all ML bricks needed by this widget.
354    * @return an array of labels for all ML bricks needed.
355    */
356   getLabels : function() {
357      var labels = [];
358      jQuery.each(this.texts, function(i, text) {
359         labels.push(text);
360      });
361      return labels;
362   },
363   
364   isValidationSuspended : function() {
365      return this.validationSuspended;
366   },
367   
368   suspendValidation : function() {
369      this.validationSuspended = true;
370   },
371   
372   resumeValidation : function() {
373      this.validationSuspended = false;
374   },
375
376   /**
377    * hook for changing or initializing the language.
378    * @param bricks map of labels to ML bricks for the new language.
379    */
380   changeLanguage : function(bricks) {},
381
382   /**
383    * bind a handler to an event
384    * @param name name of the event
385    * @param callback the handler to be called when the event is triggered
386    * @param staticParams default parameters for the handler (optional)
387    * @return this
388    */
389   bind : function(name, callback, staticParams) {
390      this[name](callback, staticParams);
391      return this;
392   },
393
394   /**
395    * unbind a handler from an event
396    * @param name the name of the event
397    * @param callback the handler to be removed (if omitted all handlers are removed)
398    * @return this
399    */
400   unbind : function(name, callback) {
401      if (callback && typeof(this.handlers[name]) != 'undefined') {
402         var self = this;
403         jQuery.each(self.handlers[name], function (i, handler) {
404            if (handler.callback == callback) {
405               self.handlers[name] = self.handlers[name].splice(i, 1);
406               return false;
407            } else {
408               return true;
409            }
410         });
411      } else {
412         this.handlers[name] = [];
413      }
414      return this;
415   },
416
417   /**
418    * trigger an event
419    * @param name the event to be triggered
420    * @param extraParams additional parameters to be passed to the event
421    * @return this
422    */
423   trigger : function(name, extraParams) {
424      this[jQuery.CbEvent.getHandleName(name)](extraParams || {});
425
426      if (typeof(this.handlers[name]) != 'undefined') {
427         jQuery.each(this.handlers[name], function(i, handler) {
428            var params = jQuery.extend({}, handler.params, extraParams || {});
429            handler.callback(params);
430            return true;
431         });
432      }
433      return this;
434   },
435
436   /**
437    * get the width of this widget
438    * @return the width
439    */
440   width : function() {
441      return this.element().width();
442   },
443
444   /**
445    * get the height of this widget
446    * @return the height
447    */
448   height : function() {
449      return this.element().height();
450   },
451
452   /**
453    * resize the widget in horizontal direction
454    * @param x the new width in pixels
455    * @return this
456    */
457   resizeX : function(x) {
458      this.element().width(x);
459      return this;
460   },
461
462   /**
463    * resize the widget in vertical direction
464    * @param y the new height in pixels
465    * @return this
466    */
467   resizeY : function(y) {
468      this.element().height(y);
469      return this;
470   },
471
472   /**
473    * resize the widget in both directions
474    * @param x the new width
475    * @param y the new height
476    * @return this
477    */
478   resize : function(x, y) {
479      this.resizeX(x);
480      this.resizeY(y);
481      return this;
482   },
483
484   /**
485    * move the widget in horizontal direction
486    * @param x the new position in pixels
487    * @return this
488    */
489   moveToX : function(x) {
490      this.element().css('left', x + 'px');
491      return this;
492   },
493
494   /**
495    * move the widget in vertical direction
496    * @param y the new position in pixels
497    * @return this
498    */
499   moveToY : function(y) {
500      this.element().css('top', y + 'px');
501      return this;
502   },
503
504   /**
505    * move the widget in both directions
506    * @param x the new X position
507    * @param y the new Y position
508    * @return this
509    */
510   moveTo : function(x, y) {
511      this.moveToX(x);
512      this.moveToY(y);
513      return this;
514   },
515
516   /**
517    * destroy the widget. Leave the element alone, though.
518    * As the widget doesn't create the element on construction it won't remove
519    * it on destruction. Widgets are expected to remove any extra elements they
520    * might have created and revert the original element to its original state,
521    * though.
522    */
523   handleDestroy : function() {
524      this.element().CbWidget(null);
525   }
526}, {
527
528
529   init : function() {
530      /*
531       * "ready" is triggered by the containing frame when everything has been
532       * translated and set up. The widget is not necessarily shown at that
533       * point, but it is in the DOM.
534       */
535      jQuery.CbEvent(this, 'ready');
536
537      jQuery.CbEvent(this, 'show');
538      jQuery.CbEvent(this, 'hide');
539      jQuery.CbEvent(this, 'destroy');
540      this.base();
541   }
542});
543
544
545

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.