1: <?php
2: /**
3: * Classes in this file represent various "events" for QCubed.
4: * Programmer can "hook" into these events and write custom handlers.
5: * Event-driven programming is explained in detail here: http://en.wikipedia.org/wiki/Event-driven_programming
6: *
7: * @package Events
8: */
9:
10: /**
11: * Base class of QEvents.
12: * Events are used in conjunction with actions to respond to user actions, like clicking, typing, etc.,
13: * or even programmable timer events.
14: * @property-read string $EventName the javascript event name that will be fired
15: * @property-read string $Condition a javascript condition that is tested before the event is sent
16: * @property-read integer $Delay ms delay before action is fired
17: * @property-read string $JsReturnParam the javascript used to create the strParameter that gets sent to the event handler registered with the event.
18: * @property-read string $Selector a jquery selector, causes the event to apply to child items matching the selector, and then get sent up the chain to this object
19: *
20: *
21: */
22: abstract class QEvent extends QBaseClass {
23: /** @var string|null The JS condition in which an event would fire */
24: protected $strCondition = null;
25: /** @var int|mixed The number of second after which the event has to be fired */
26: protected $intDelay = 0;
27: protected $strSelector = null;
28:
29: /**
30: * Create an event.
31: * @param integer $intDelay ms delay to wait before action is fired
32: * @param string $strCondition javascript condition to check before firing the action
33: * @param string $strSelector jquery selector to cause event to be attached to child items instead of this item
34: * @throws Exception|QCallerException
35: */
36: public function __construct($intDelay = 0, $strCondition = null, $strSelector = null) {
37: try {
38: if ($intDelay)
39: $this->intDelay = QType::Cast($intDelay, QType::Integer);
40: if ($strCondition) {
41: if ($this->strCondition)
42: $this->strCondition = sprintf('(%s) && (%s)', $this->strCondition, $strCondition);
43: else
44: $this->strCondition = QType::Cast($strCondition, QType::String);
45: }
46: if ($strSelector) {
47: $this->strSelector = $strSelector;
48: }
49: } catch (QCallerException $objExc) {
50: $objExc->IncrementOffset();
51: throw $objExc;
52: }
53: }
54:
55: /**
56: * The PHP Magic function for this class
57: * @param string $strName Name of the property to fetch
58: *
59: * @return int|mixed|null|string
60: * @throws Exception|QCallerException
61: */
62: public function __get($strName) {
63: switch ($strName) {
64: case 'EventName':
65: $strEvent = constant(get_class($this).'::EventName');
66: if ($this->strSelector) {
67: $strEvent .= '","' . addslashes($this->strSelector);
68: }
69: return $strEvent;
70: case 'Condition':
71: return $this->strCondition;
72: case 'Delay':
73: return $this->intDelay;
74: case 'JsReturnParam':
75: $strConst = get_class($this).'::JsReturnParam';
76: return defined($strConst) ? constant($strConst) : '';
77: case 'Selector':
78: return $this->strSelector;
79:
80: default:
81: try {
82: return parent::__get($strName);
83: } catch (QCallerException $objExc) {
84: $objExc->IncrementOffset();
85: throw $objExc;
86: }
87: }
88: }
89: }
90:
91: /**
92: * Blur event: keyboard focus moving away from the control.
93: */
94: class QBlurEvent extends QEvent {
95: /** Event Name */
96: const EventName = 'blur';
97: }
98:
99: /**
100: * Be careful with change events for listboxes -
101: * they don't fire when the user picks a value on many browsers!
102: */
103: class QChangeEvent extends QEvent {
104: /** Event Name */
105: const EventName = 'change';
106: }
107:
108: /** Click event: when the control recieves a mouse click */
109: class QClickEvent extends QEvent {
110: /** Event Name */
111: const EventName = 'click';
112: }
113:
114: /** Double-Click event: when the control recieves a double click */
115: class QDoubleClickEvent extends QEvent {
116: /** Event Name */
117: const EventName = 'dblclick';
118: }
119:
120: /** Drop event: When an element is dropped onto another element */
121: class QDragDropEvent extends QEvent {
122: /** Event Name */
123: const EventName = 'drop';
124: }
125:
126: /**
127: * Focus event: keyboard focus entering the control.
128: */
129: class QFocusEvent extends QEvent {
130: /** Event Name */
131: const EventName = 'focus';
132: }
133:
134: /** added for V2 / jQuery support */
135: class QFocusInEvent extends QEvent {
136: /** Event Name */
137: const EventName = 'focusin';
138: }
139:
140: /** added for V2 / jQuery support */
141: class QFocusOutEvent extends QEvent {
142: /** Event Name */
143: const EventName = 'focusout';
144: }
145:
146: /** When a keyboard key is pressed down (without having been released) while the control is in focus */
147: class QKeyDownEvent extends QEvent {
148: /** Event Name */
149: const EventName = 'keydown';
150: }
151:
152: /** When a keyboard key has been pressed (key went down, and went up) */
153: class QKeyPressEvent extends QEvent {
154: /** Event Name */
155: const EventName = 'keypress';
156: }
157:
158: /** When a pressed key goes up while the focus is on the control */
159: class QKeyUpEvent extends QEvent {
160: /** Event Name */
161: const EventName = 'keyup';
162: }
163:
164: /** Mouse button was pressed down on the control */
165: class QMouseDownEvent extends QEvent {
166: /** Event Name */
167: const EventName = 'mousedown';
168: }
169:
170: /** When the mouse cursor enters the control */
171: class QMouseEnterEvent extends QEvent {
172: /** Event Name */
173: const EventName = 'mouseenter';
174: }
175:
176: /** When the mouse cursor leaves the control */
177: class QMouseLeaveEvent extends QEvent {
178: /** Event Name */
179: const EventName = 'mouseleave';
180: }
181:
182: /** When the mouse pointer moves within the control on the browser */
183: class QMouseMoveEvent extends QEvent {
184: /** Event Name */
185: const EventName = 'mousemove';
186: }
187:
188: /** When the mouse cursor leaves the control and any of its children */
189: class QMouseOutEvent extends QEvent {
190: /** Event Name */
191: const EventName = 'mouseout';
192: }
193:
194: /** When the mouse is over the control or an element inside it */
195: class QMouseOverEvent extends QEvent {
196: /** Event Name */
197: const EventName = 'mouseover';
198: }
199:
200: /** When the left mouse button is released (after being pressed) from over the control */
201: class QMouseUpEvent extends QEvent {
202: /** Event Name */
203: const EventName = 'mouseup';
204: }
205:
206: /** When the control/element is selected */
207: class QSelectEvent extends QEvent {
208: /** Event Name */
209: const EventName = 'select';
210: }
211:
212: /** Override right clicks */
213: class QContextMenuEvent extends QEvent {
214: /** Event Name */
215: const EventName = 'contextmenu';
216: }
217:
218: /** When enter key is pressed while the control is in focus */
219: class QEnterKeyEvent extends QKeyDownEvent {
220: /** @var string Condition JS */
221: protected $strCondition = 'event.keyCode == 13';
222: }
223:
224: /** When the escape key is pressed while the control is in focus */
225: class QEscapeKeyEvent extends QKeyDownEvent {
226: /** @var string Condition JS */
227: protected $strCondition = 'event.keyCode == 27';
228: }
229:
230: /** When the up arrow key is pressed while the element is in focus */
231: class QUpArrowKeyEvent extends QKeyDownEvent {
232: /** @var string Condition JS */
233: protected $strCondition = 'event.keyCode == 38';
234: }
235:
236: /** When the down arrow key is pressed while the element is in focus */
237: class QDownArrowKeyEvent extends QKeyDownEvent {
238: /** @var string Condition JS */
239: protected $strCondition = 'event.keyCode == 40';
240: }
241:
242: /** When the Tab key is pressed with element in focus */
243: class QTabKeyEvent extends QKeyDownEvent {
244: /** @var string Condition JS with keycode for tab key */
245: protected $strCondition = 'event.keyCode == 9';
246: }
247:
248: /** When the Backspace key is pressed with element in focus */
249: class QBackspaceKeyEvent extends QKeyDownEvent {
250: /** @var string Condition JS with keycode for escape key */
251: protected $strCondition = 'event.keyCode == 8';
252: }
253:
254: /**
255: * Detects changes to textboxes and other input elements. Responds to cut/paste, search cancel, etc.
256: * Ignores arrow keys, etc.
257: * Not in IE8 or below. Buggy in IE9. Full support in IE10 and above.
258: * No support in Safari 5 and below for textarea elements.
259: */
260: class QInputEvent extends QEvent {
261: /** Event Name */
262: const EventName = 'input';
263: }
264:
265: /**
266: * Class QJqUiEvent: When an event is triggered by jQuery-UI (drag, drop, resize etc.)
267: * @abstract Implementation in children class
268: */
269: abstract class QJqUiEvent extends QEvent {
270: // be sure to subclass your events from this class if they are JqUiEvents
271: }
272:
273: /**
274: * Class QJqUiPropertyEvent: When properties of a jQuery-UI widget change
275: * Currently, Date-Time related jQuery-UI controls are derived from this one
276: *
277: * @property-read string $JqProperty The property string
278: */
279: abstract class QJqUiPropertyEvent extends QEvent {
280: // be sure to subclass your events from this class if they are JqUiEvents
281: /** @var string The property JS string */
282: protected $strJqProperty = '';
283:
284: /**
285: * PHP Magic method to get properties from this class
286: * @param string $strName
287: *
288: * @return mixed
289: * @throws Exception|QCallerException
290: */
291: public function __get($strName) {
292: switch ($strName) {
293: case 'JqProperty':
294: return $this->strJqProperty;
295: default:
296: try {
297: return parent::__get($strName);
298: } catch (QCallerException $objExc) {
299: $objExc->IncrementOffset();
300: throw $objExc;
301: }
302: }
303: }
304: }
305:
306:
307: /**
308: *
309: * a custom event with event delegation
310: * With this event you can delegate any jquery event of child controls or any html element
311: * to a parent. By using the selector you can limit the event sources this event
312: * gets triggered from. You can use a css class (or any jquery selector) for
313: * $strSelector. Example ( new QJsDelegateEvent("click",".remove",new QAjaxControlAction( ... )); )
314: *
315: * This event can help you reduce the produced javascript to a minimum.
316: * One positive side effect is that this event will also work for html child elements added
317: * in the future (after the event was created).
318: *
319: * @param string $strEventName the name of the event i.e.: "click"
320: * @param string $strSelector i.e.: "#myselector" ==> results in: $('#myControl').on("myevent","#myselector",function()...
321: * @deprectated QEvent now has the strSelector at the end of its constructor
322: *
323: */
324: class QOnEvent extends QEvent{
325: /** @var string Name of the event */
326: protected $strEventName;
327:
328: /**
329: * Constructor
330: * @param int $strEventName
331: * @param int $intDelay
332: * @param string $strCondition
333: * @param string $strSelector
334: * @throws Exception|QCallerException
335: */
336: public function __construct($strEventName, $intDelay = 0, $strCondition = null, $strSelector = null) {
337: $this->strEventName=$strEventName;
338: if ($strSelector) {
339: $strSelector = addslashes($strSelector);
340: $this->strEventName .= '","'.$strSelector;
341: }
342:
343: try {
344: parent::__construct($intDelay,$strCondition, $strSelector);
345: } catch (QCallerException $objExc) {
346: $objExc->IncrementOffset();
347: throw $objExc;
348: }
349: }
350:
351: /**
352: * PHP Magic function implementation
353: * @param string $strName
354: *
355: * @return int|mixed|null|string
356: * @throws Exception|QCallerException
357: */
358: public function __get($strName) {
359: switch ($strName) {
360: case 'EventName':
361: return $this->strEventName;
362: default:
363: try {
364: return parent::__get($strName);
365: } catch (QCallerException $objExc) {
366: $objExc->IncrementOffset();
367: throw $objExc;
368: }
369: }
370: }
371:
372: }
373:
374: /**
375: * Class QCellClickEvent
376: * An event to detect clicking on a table cell.
377: * Lots of things can be determined using this event by changing the JsReturnParam values. When this event fires,
378: * the javascript environment will have the following local variables defined:
379: * - this: The html object for the cell clicked.
380: * - event: The event object for the click.
381: *
382: * Here are some examples of return params you can specify to return data to your action handler:
383: * this.id - the cell id
384: * this.tagName - the tag for the cell (either th or td)
385: * this.cellIndex - the column index that was clicked on, starting on the left with column zero
386: * $j(this).data('value') - the "data-value" attribute of the cell (if you specify one). Use this formula for any kind of "data-" attribute.
387: * $j(this).parent() - the jQuery row object
388: * $j(this).parent()[0] - the html row object
389: * $j(this).parent()[0].rowIndex - the index of the row clicked, starting with zero at the top (including any header rows).
390: * $j(this).parent().attr('id') or $j(this).parent()[0].id - the id of the row clicked on
391: * $j(this).parent().data("value") - the "data-value" attribute of the row. Use this formula for any kind of "data-" attribute.
392: * $j(this).parent().closest('table').find('thead').find('th')[this.cellIndex].id - the id of the column clicked in
393: * event.target - the html object clicked in. If your table cell had other objects in it, this will return the
394: * object clicked inside the cell. This could be important, for example, if you had form objects inside the cell,
395: * and you wanted to behave differently if a form object was clicked on, verses clicking outside the form object.
396: *
397: * You can put your items in a javascript array, and an array will be returned as the strParameter in the action.
398: * Or you can put it in a javascript object, and a named array(hash) will be returned.
399: *
400: * The default returns the array(row=>rowIndex, col=>colIndex), but you can override this with your action. For
401: * example:
402: *
403: * new QAjaxAction ('yourFunction', null, 'this.cellIndex')
404: *
405: * will return the column index into the strParameter, instead of the default.
406: */
407: class QCellClickEvent extends QClickEvent {
408: // Shortcuts to specify common return parameters
409: const RowIndex = '$j(this).parent()[0].rowIndex';
410: const ColumnIndex = 'this.cellIndex';
411: const CellId = 'this.id';
412: const RowId = '$j(this).parent().attr("id")';
413: const RowValue = '$j(this).parent().data("value")';
414: const ColId = '$j(this).parent().closest("table").find("thead").find("th")[this.cellIndex].id';
415:
416: protected $strReturnParam;
417:
418: public function __construct($intDelay = 0, $strCondition = null, $mixReturnParams = null) {
419: parent::__construct($intDelay, $strCondition, 'th,td');
420:
421: if (!$mixReturnParams) {
422: $this->strReturnParam = '{"row": $j(this).parent()[0].rowIndex, "col": this.cellIndex}'; // default returns the row and colum indexes of the cell clicked
423: }
424: else if (is_array($mixReturnParams)) {
425: $combined = array_map(function($key, $val) {
426: return '"' . $key . '":' . $val;
427: }, array_keys($mixReturnParams), array_values($mixReturnParams));
428:
429: $this->strReturnParam = '{' . implode(',', $combined) . '}';
430: }
431: elseif (is_string($mixReturnParams)) {
432: $this->strReturnParam = $mixReturnParams;
433: }
434: }
435:
436: /**
437: * Returns the javascript that returns the row data value into a param
438: * @param $strKey
439: * @return string
440: */
441: public static function RowDataValue($strKey) {
442: return '$j(this).parent().data("' . $strKey . '")';
443: }
444:
445: /**
446: * Same for the cell.
447: *
448: * @param $strKey
449: * @return string
450: */
451: public static function CellDataValue($strKey) {
452: return '$j(this).data("' . $strKey . '")';
453: }
454:
455:
456: public function __get($strName) {
457: switch($strName) {
458: case 'JsReturnParam':
459: return $this->strReturnParam;
460:
461: default:
462: try {
463: return parent::__get($strName);
464: } catch (QCallerException $objExc) {
465: $objExc->IncrementOffset();
466: throw $objExc;
467: }
468:
469: }
470: }
471: }