PageRenderTime 71ms CodeModel.GetById 37ms RepoModel.GetById 1ms app.codeStats 0ms

/js/yii/base/CComponent.js

http://github.com/phpnode/YiiJS
JavaScript | 758 lines | 415 code | 15 blank | 328 comment | 141 complexity | 56a6792104a440b13d472142c521662f MD5 | raw file
  1. /*global Yii, php, $, jQuery, alert, clearInterval, clearTimeout, document, event, frames, history, Image, location, name, navigator, Option, parent, screen, setInterval, setTimeout, window, XMLHttpRequest */
  2. /**
  3. * CComponent is the base class for all components.
  4. *
  5. * CComponent implements the protocol of defining, using properties and events.
  6. *
  7. * A property is defined by a getter method, and/or a setter method.
  8. * Properties can be accessed in the way like accessing normal object members.
  9. * Reading or writing a property will cause the invocation of the corresponding
  10. * getter or setter method, e.g
  11. * <pre>
  12. * a=component.text; // equivalent to $a=$component->getText();
  13. * component.text='abc'; // equivalent to $component->setText('abc');
  14. * </pre>
  15. * The signatures of getter and setter methods are as follows,
  16. * <pre>
  17. * // getter, defines a readable property 'text'
  18. * public function getText() { +++ }
  19. * // setter, defines a writable property 'text' with $value to be set to the property
  20. * public function setText(value) { +++ }
  21. * </pre>
  22. *
  23. * An event is defined by the presence of a method whose name starts with 'on'.
  24. * The event name is the method name. When an event is raised, functions
  25. * (called event handlers) attached to the event will be invoked automatically.
  26. *
  27. * An event can be raised by calling {@link raiseEvent} method, upon which
  28. * the attached event handlers will be invoked automatically in the order they
  29. * are attached to the event. Event handlers must have the following signature,
  30. * <pre>
  31. * function eventHandler(event) { +++ }
  32. * </pre>
  33. * where $event includes parameters associated with the event.
  34. *
  35. * To attach an event handler to an event, see {@link attachEventHandler}.
  36. * You can also use the following syntax:
  37. * <pre>
  38. * component.onClick=callback; // or $component->onClick->add($callback);
  39. * </pre>
  40. * where $callback refers to a valid PHP callback. Below we show some callback examples:
  41. * <pre>
  42. * 'handleOnClick' // handleOnClick() is a global function
  43. * [object,'handleOnClick'] // using $object->handleOnClick()
  44. * ['Page','handleOnClick'] // using Page::handleOnClick()
  45. * </pre>
  46. *
  47. * To raise an event, use {@link raiseEvent}. The on-method defining an event is
  48. * commonly written like the following:
  49. * <pre>
  50. * public function onClick(event)
  51. * {
  52. * this.raiseEvent('onClick',event);
  53. * }
  54. * </pre>
  55. * where <code>$event</code> is an instance of {@link CEvent} or its child class.
  56. * One can then raise the event by calling the on-method instead of {@link raiseEvent} directly.
  57. *
  58. * Both property names and event names are case-insensitive.
  59. *
  60. * Starting from version 1.0.2, CComponent supports behaviors. A behavior is an
  61. * instance of {@link IBehavior} which is attached to a component. The methods of
  62. * the behavior can be invoked as if they belong to the component. Multiple behaviors
  63. * can be attached to the same component.
  64. *
  65. * To attach a behavior to a component, call {@link attachBehavior}; and to detach the behavior
  66. * from the component, call {@link detachBehavior}.
  67. *
  68. * A behavior can be temporarily enabled or disabled by calling {@link enableBehavior}
  69. * or {@link disableBehavior}, respectively. When disabled, the behavior methods cannot
  70. * be invoked via the component.
  71. *
  72. * Starting from version 1.1.0, a behavior's properties (either its public member variables or
  73. * its properties defined via getters and/or setters) can be accessed through the component it
  74. * is attached to.
  75. *
  76. * @originalAuthor Qiang Xue <qiang.xue@gmail.com>
  77. * @version $Id: CComponent.php 3066 2011-03-13 14:22:55Z qiang.xue $
  78. * @package system.base
  79. * @since 1.0
  80. * @author Charles Pick
  81. * @class
  82. */
  83. Yii.CComponent = function CComponent() {
  84. };
  85. Yii.CComponent.prototype._e = null;
  86. Yii.CComponent.prototype._m = null;
  87. /**
  88. * Gets the class name for this item.
  89. * Since JavaScript doesn't really support this we
  90. * abuse function declarations to implement it,
  91. * for example instead of:
  92. * <pre>
  93. * Yii.Blah = function() { ... }
  94. * </pre>
  95. * we use:
  96. * <pre>
  97. * Yii.Blah = function Blah() { ... }
  98. * </pre>
  99. * We can now retrieve the name of the class by inspecting the constructor.
  100. */
  101. Yii.CComponent.prototype.getClassName = function() {
  102. var matches, className;
  103. matches = /function(.*)\((.*)\)/.exec((this).constructor);
  104. if (matches) {
  105. return php.trim(matches[1]);
  106. }
  107. };
  108. /**
  109. * Returns a property value, an event handler list or a behavior based on its name.
  110. * Do not call this method. This is a PHP magic method that we override
  111. * to allow using the following syntax to read a property or obtain event handlers:
  112. * <pre>
  113. * value=component.propertyName;
  114. * handlers=component.eventName;
  115. * </pre>
  116. * @param {String} name the property name or event name
  117. * @returns {Mixed} the property value, event handlers attached to the event, or the named behavior (since version 1.0.2)
  118. * @throws {Yii.CException} if the property or event is not defined
  119. * @see __set
  120. */
  121. Yii.CComponent.prototype.get = function (name) {
  122. var getter, i, object, nameParts = [], limit;
  123. if (name.indexOf !== undefined && name.indexOf(".") !== -1) {
  124. nameParts = name.split(".");
  125. name = nameParts.shift();
  126. }
  127. if (this[name] !== undefined) {
  128. object = this[name];
  129. if (nameParts.length > 0) {
  130. if (object instanceof Yii.CComponent) {
  131. return object.get(nameParts.join("."));
  132. }
  133. limit = nameParts.length;
  134. for (i = 0; i < limit; i++) {
  135. name = nameParts.shift();
  136. object = object[name];
  137. if (nameParts.length === 0) {
  138. return object;
  139. }
  140. if (object instanceof Yii.CComponent) {
  141. return object.get(nameParts.join("."));
  142. }
  143. }
  144. }
  145. return object;
  146. }
  147. getter='get'+php.ucfirst(name);
  148. if(php.method_exists(this,getter)) {
  149. object = this[getter]();
  150. if (nameParts.length > 0) {
  151. if (object instanceof Yii.CComponent) {
  152. return object.get(nameParts.join("."));
  153. }
  154. limit = nameParts.length;
  155. for (i = 0; i < limit; i++) {
  156. name = nameParts.shift();
  157. object = object[name];
  158. if (nameParts.length === 0) {
  159. return object;
  160. }
  161. if (object instanceof Yii.CComponent) {
  162. return object.get(nameParts.join("."));
  163. }
  164. }
  165. }
  166. return object;
  167. }
  168. else if(php.strncasecmp(name,'on',2)===0 && php.method_exists(this,name)) {
  169. // duplicating getEventHandlers() here for performance
  170. name=name.toLowerCase();
  171. if(this._e[name] === undefined) {
  172. this._e[name]=new Yii.CList();
  173. }
  174. return this._e[name];
  175. }
  176. else if(this._m !== null && this._m[name] !== undefined) {
  177. return this._m[name];
  178. }
  179. else if(this._m !== null) {
  180. for (i in this._m) {
  181. if (this._m.hasOwnProperty(i)) {
  182. object = this._m[i];
  183. try {
  184. if(object.getEnabled() && (php.property_exists(object,name) || object.canGetProperty(name))) {
  185. if (nameParts.length > 0) {
  186. return object.get(nameParts.join("."));
  187. }
  188. return object.get(name);
  189. }
  190. }
  191. catch (e) {
  192. console.log(e);
  193. }
  194. }
  195. }
  196. }
  197. console.log(this.getClassName() + " : " + name);
  198. throw new Yii.CException(Yii.t('yii','Property "{class}.{property}" is not defined.',
  199. {'{class}':this.getClassName(), '{property}':name}));
  200. };
  201. /**
  202. * Sets value of a component property.
  203. * Do not call this method. This is a PHP magic method that we override
  204. * to allow using the following syntax to set a property or attach an event handler
  205. * <pre>
  206. * this.propertyName=value;
  207. * this.eventName=callback;
  208. * </pre>
  209. * @param {String} name the property name or the event name
  210. * @param {Mixed} value the property value or callback
  211. * @throws {Yii.CException} if the property/event is not defined or the property is read only.
  212. * @see __get
  213. */
  214. Yii.CComponent.prototype.set = function (name, value) {
  215. var setter, i, object, nameParts = [];
  216. if (name.indexOf(".") !== -1) {
  217. nameParts = name.split(".");
  218. name = nameParts.pop();
  219. return (this.get(nameParts.join("."))[name] = value);
  220. }
  221. if (this[name] !== undefined) {
  222. return (this[name] = value);
  223. }
  224. setter='set'+php.ucfirst(name);
  225. if(php.method_exists(this,setter)) {
  226. return this[setter](value);
  227. }
  228. else if(php.strncasecmp(name,'on',2)===0 && php.method_exists(this,name)) {
  229. // duplicating getEventHandlers() here for performance
  230. name=name.toLowerCase();
  231. if(this._e[name] === undefined) {
  232. this._e[name]=new Yii.CList();
  233. }
  234. return this._e[name].add(value);
  235. }
  236. else if(this._m !== null) {
  237. for (i in this._m) {
  238. if (this._m.hasOwnProperty(i)) {
  239. object = this._m[i];
  240. if(object.getEnabled() && (php.property_exists(object,name) || object.canSetProperty(name))) {
  241. return (object.set(name,value));
  242. }
  243. }
  244. }
  245. }
  246. if(php.method_exists(this,'get'+php.ucfirst(name))) {
  247. throw new Yii.CException(Yii.t('yii','Property "{class}.{property}" is read only.',
  248. {'{class}':this.getClassName(), '{property}':name}));
  249. }
  250. else {
  251. throw new Yii.CException(Yii.t('yii','Property "{class}.{property}" is not defined.',
  252. {'{class}':this.getClassName(), '{property}':name}));
  253. }
  254. };
  255. /**
  256. * Checks if a property value is null.
  257. * Do not call this method. This is a PHP magic method that we override
  258. * to allow using isset() to detect if a component property is set or not.
  259. * @param {String} name the property name or the event name
  260. * @since 1.0.1
  261. */
  262. Yii.CComponent.prototype.isset = function (name) {
  263. var getter, i, object, nameParts = [], value;
  264. if (name.indexOf(".") !== -1) {
  265. nameParts = name.split(".");
  266. name = nameParts.pop();
  267. try {
  268. value = this.get(nameParts.join("."))[name];
  269. if (value !== undefined && value !== null) {
  270. return true;
  271. }
  272. return false;
  273. }
  274. catch (e) {
  275. return false;
  276. }
  277. }
  278. if (this[name] !== undefined) {
  279. return true;
  280. }
  281. getter='get'+php.ucfirst(name);
  282. if(php.method_exists(this,getter)) {
  283. return (this[getter]()!==null);
  284. }
  285. else if(php.strncasecmp(name,'on',2)===0 && php.method_exists(this,name))
  286. {
  287. name=name.toLowerCase();
  288. return this._e !== null && this._e[name] !== undefined && this._e[name].getCount();
  289. }
  290. else if(this._m !== null) {
  291. if(this._m[name] !== undefined) {
  292. return true;
  293. }
  294. for (i in this._m) {
  295. if (this._m.hasOwnProperty(i)) {
  296. object = this._m[i];
  297. if(object.getEnabled() && (php.property_exists(object,name) || object.canGetProperty(name))) {
  298. return true;
  299. }
  300. }
  301. }
  302. }
  303. return false;
  304. };
  305. /**
  306. * Sets a component property to be null.
  307. * Do not call this method. This is a PHP magic method that we override
  308. * to allow using unset() to set a component property to be null.
  309. * @param {String} name the property name or the event name
  310. * @throws {Yii.CException} if the property is read only.
  311. * @since 1.0.1
  312. */
  313. Yii.CComponent.prototype.unset = function (name) {
  314. var setter, i, object, nameParts = [];
  315. if (name.indexOf(".") !== -1) {
  316. nameParts = name.split(".");
  317. name = nameParts.pop();
  318. object = this.get(nameParts.join("."))[name];
  319. if (object.unset !== undefined) {
  320. return object.unset(name);
  321. }
  322. return (this.get(nameParts.join("."))[name] = null);
  323. }
  324. setter='set'+php.ucfirst(name);
  325. if (this[name] !== undefined) {
  326. this[name] = null;
  327. return;
  328. }
  329. else if(php.method_exists(this,setter)) {
  330. this[setter](null);
  331. }
  332. else if(php.strncasecmp(name,'on',2)===0 && php.method_exists(this,name)) {
  333. delete this._e[name.toLowerCase()];
  334. }
  335. else if(this._m !== null)
  336. {
  337. if(this._m[name] !== undefined) {
  338. this.detachBehavior(name);
  339. }
  340. else
  341. {
  342. for (i in this._m) {
  343. if (this._m.hasOwnProperty(i)) {
  344. object = this._m[i];
  345. if(object.getEnabled()) {
  346. if(php.property_exists(object,name)) {
  347. return (object[name]=null);
  348. }
  349. else if(object.canSetProperty(name)) {
  350. return object[setter](null);
  351. }
  352. }
  353. }
  354. }
  355. }
  356. }
  357. else if(php.method_exists(this,'get'+name)) {
  358. throw new Yii.CException(Yii.t('yii','Property "{class}.{property}" is read only.',
  359. {'{class}':this.getClassName(), '{property}':name}));
  360. }
  361. };
  362. /**
  363. * Calls the named method which is not a class method.
  364. * Do not call this method. This is a PHP magic method that we override
  365. * to implement the behavior feature.
  366. * @param {String} name the method name
  367. * @param {Array} parameters method parameters
  368. * @returns {Mixed} the method return value
  369. * @since 1.0.2
  370. */
  371. Yii.CComponent.prototype.call = function (name, parameters) {
  372. var i, object;
  373. if (this[name] !== undefined) {
  374. return php.call_user_func_array([this,name],parameters);
  375. }
  376. else if(this._m!==null) {
  377. for (i in this._m) {
  378. if (this._m.hasOwnProperty(i)) {
  379. object = this._m[i];
  380. if(object.getEnabled() && php.method_exists(object,name)) {
  381. return php.call_user_func_array([object,name],parameters);
  382. }
  383. }
  384. }
  385. }
  386. throw new Yii.CException(Yii.t('yii','{class} does not have a method named "{name}".',
  387. {'{class}':this.getClassName(), '{name}':name}));
  388. };
  389. /**
  390. * Returns the named behavior object.
  391. * The name 'asa' stands for 'as a'.
  392. * @param {String} behavior the behavior name
  393. * @returns {IBehavior} the behavior object, or null if the behavior does not exist
  394. * @since 1.0.2
  395. */
  396. Yii.CComponent.prototype.asa = function (behavior) {
  397. return this._m !== null && this._m[behavior] !== undefined ? this._m[behavior] : null;
  398. };
  399. /**
  400. * Attaches a list of behaviors to the component.
  401. * Each behavior is indexed by its name and should be an instance of
  402. * {@link IBehavior}, a string specifying the behavior class, or an
  403. * array of the following structure:
  404. * <pre>
  405. * {
  406. * 'class':'path.to.BehaviorClass',
  407. * 'property1':'value1',
  408. * 'property2':'value2',
  409. * }
  410. * </pre>
  411. * @param {Array} behaviors list of behaviors to be attached to the component
  412. * @since 1.0.2
  413. */
  414. Yii.CComponent.prototype.attachBehaviors = function (behaviors) {
  415. var name, behavior;
  416. for (name in behaviors) {
  417. if (behaviors.hasOwnProperty(name)) {
  418. behavior = behaviors[name];
  419. this.attachBehavior(name,behavior);
  420. }
  421. }
  422. };
  423. /**
  424. * Detaches all behaviors from the component.
  425. * @since 1.0.2
  426. */
  427. Yii.CComponent.prototype.detachBehaviors = function () {
  428. var name, behavior;
  429. if(this._m!==null) {
  430. for (name in this._m) {
  431. if (this._m.hasOwnProperty(name)) {
  432. behavior = this._m[name];
  433. this.detachBehavior(name);
  434. }
  435. }
  436. this._m=null;
  437. }
  438. };
  439. /**
  440. * Attaches a behavior to this component.
  441. * This method will create the behavior object based on the given
  442. * configuration. After that, the behavior object will be initialized
  443. * by calling its {@link IBehavior::attach} method.
  444. * @param {String} name the behavior's name. It should uniquely identify this behavior.
  445. * @param {Mixed} behavior the behavior configuration. This is passed as the first
  446. * parameter to {@link YiiBase::createComponent} to create the behavior object.
  447. * @returns {IBehavior} the behavior object
  448. * @since 1.0.2
  449. */
  450. Yii.CComponent.prototype.attachBehavior = function (name, behavior) {
  451. if(!(behavior instanceof Yii.CBehavior)) {
  452. behavior=Yii.createComponent(behavior);
  453. }
  454. behavior.setEnabled(true);
  455. behavior.attach(this);
  456. if (this._m === null) {
  457. this._m = {};
  458. }
  459. return (this._m[name]=behavior);
  460. };
  461. /**
  462. * Detaches a behavior from the component.
  463. * The behavior's {@link IBehavior::detach} method will be invoked.
  464. * @param {String} name the behavior's name. It uniquely identifies the behavior.
  465. * @returns {IBehavior} the detached behavior. Null if the behavior does not exist.
  466. * @since 1.0.2
  467. */
  468. Yii.CComponent.prototype.detachBehavior = function (name) {
  469. var behavior;
  470. if(this._m[name] !== undefined) {
  471. this._m[name].detach(this);
  472. behavior=this._m[name];
  473. delete this._m[name];
  474. return behavior;
  475. }
  476. };
  477. /**
  478. * Enables all behaviors attached to this component.
  479. * @since 1.0.2
  480. */
  481. Yii.CComponent.prototype.enableBehaviors = function () {
  482. var i, behavior;
  483. if(this._m!==null) {
  484. for (i in this._m) {
  485. if (this._m.hasOwnProperty(i)) {
  486. behavior = this._m[i];
  487. behavior.setEnabled(true);
  488. }
  489. }
  490. }
  491. };
  492. /**
  493. * Disables all behaviors attached to this component.
  494. * @since 1.0.2
  495. */
  496. Yii.CComponent.prototype.disableBehaviors = function () {
  497. var i, behavior;
  498. if(this._m!==null) {
  499. for (i in this._m) {
  500. if (this._m.hasOwnProperty(i)) {
  501. behavior = this._m[i];
  502. behavior.setEnabled(false);
  503. }
  504. }
  505. }
  506. };
  507. /**
  508. * Enables an attached behavior.
  509. * A behavior is only effective when it is enabled.
  510. * A behavior is enabled when first attached.
  511. * @param {String} name the behavior's name. It uniquely identifies the behavior.
  512. * @since 1.0.2
  513. */
  514. Yii.CComponent.prototype.enableBehavior = function (name) {
  515. if(this._m !== null && this._m[name] !== undefined) {
  516. this._m[name].setEnabled(true);
  517. }
  518. };
  519. /**
  520. * Disables an attached behavior.
  521. * A behavior is only effective when it is enabled.
  522. * @param {String} name the behavior's name. It uniquely identifies the behavior.
  523. * @since 1.0.2
  524. */
  525. Yii.CComponent.prototype.disableBehavior = function (name) {
  526. if(this._m !== null && this._m[name] !== undefined) {
  527. this._m[name].setEnabled(false);
  528. }
  529. };
  530. /**
  531. * Determines whether a property is defined.
  532. * A property is defined if there is a getter or setter method
  533. * defined in the class. Note, property names are case-insensitive.
  534. * @param {String} name the property name
  535. * @returns {Boolean} whether the property is defined
  536. * @see canGetProperty
  537. * @see canSetProperty
  538. */
  539. Yii.CComponent.prototype.hasProperty = function (name) {
  540. return this[name] !== undefined || php.method_exists(this,'get'+php.ucfirst(name)) || php.method_exists(this,'set'+php.ucfirst(name));
  541. };
  542. /**
  543. * Determines whether a property can be read.
  544. * A property can be read if the class has a getter method
  545. * for the property name. Note, property name is case-insensitive.
  546. * @param {String} name the property name
  547. * @returns {Boolean} whether the property can be read
  548. * @see canSetProperty
  549. */
  550. Yii.CComponent.prototype.canGetProperty = function (name) {
  551. return this[name] !== undefined || php.method_exists(this,'get'+php.ucfirst(name));
  552. };
  553. /**
  554. * Determines whether a property can be set.
  555. * A property can be written if the class has a setter method
  556. * for the property name. Note, property name is case-insensitive.
  557. * @param {String} name the property name
  558. * @returns {Boolean} whether the property can be written
  559. * @see canGetProperty
  560. */
  561. Yii.CComponent.prototype.canSetProperty = function (name) {
  562. return this[name] !== undefined || php.method_exists(this,'set'+php.ucfirst(name));
  563. };
  564. /**
  565. * Determines whether an event is defined.
  566. * An event is defined if the class has a method named like 'onXXX'.
  567. * Note, event name is case-insensitive.
  568. * @param {String} name the event name
  569. * @returns {Boolean} whether an event is defined
  570. */
  571. Yii.CComponent.prototype.hasEvent = function (name) {
  572. return !php.strncasecmp(name,'on',2) && php.method_exists(this,name);
  573. };
  574. /**
  575. * Checks whether the named event has attached handlers.
  576. * @param {String} name the event name
  577. * @returns {Boolean} whether an event has been attached one or several handlers
  578. */
  579. Yii.CComponent.prototype.hasEventHandler = function (name) {
  580. return this._e !== null && this._e[name] !== undefined && this._e[name].getCount()>0;
  581. };
  582. /**
  583. * Returns the list of attached event handlers for an event.
  584. * @param {String} name the event name
  585. * @returns {Yii.CList} list of attached event handlers for the event
  586. * @throws {Yii.CException} if the event is not defined
  587. */
  588. Yii.CComponent.prototype.getEventHandlers = function (name) {
  589. if(this.hasEvent(name)) {
  590. if (this._e === null) {
  591. this._e = {};
  592. }
  593. if(this._e[name] === undefined) {
  594. this._e[name]=new Yii.CList();
  595. }
  596. return this._e[name];
  597. }
  598. else {
  599. throw new Yii.CException(Yii.t('yii','Event "{class}.{event}" is not defined.',
  600. {'{class}':this.getClassName(), '{event}':name}));
  601. }
  602. };
  603. /**
  604. * Attaches an event handler to an event.
  605. *
  606. * An event handler must be a valid PHP callback, i.e., a string referring to
  607. * a global function name, or an array containing two elements with
  608. * the first element being an object and the second element a method name
  609. * of the object.
  610. *
  611. * An event handler must be defined with the following signature,
  612. * <pre>
  613. * function handlerName(event) {}
  614. * </pre>
  615. * where $event includes parameters associated with the event.
  616. *
  617. * This is a convenient method of attaching a handler to an event.
  618. * It is equivalent to the following code:
  619. * <pre>
  620. * component.getEventHandlers(eventName).add(eventHandler);
  621. * </pre>
  622. *
  623. * Using {@link getEventHandlers}, one can also specify the excution order
  624. * of multiple handlers attaching to the same event. For example:
  625. * <pre>
  626. * component.getEventHandlers(eventName).insertAt(0,eventHandler);
  627. * </pre>
  628. * makes the handler to be invoked first.
  629. *
  630. * @param {String} name the event name
  631. * @param {Yii.Callback} handler the event handler
  632. * @throws {Yii.CException} if the event is not defined
  633. * @see detachEventHandler
  634. */
  635. Yii.CComponent.prototype.attachEventHandler = function (name, handler) {
  636. this.getEventHandlers(name).add(handler);
  637. };
  638. /**
  639. * Detaches an existing event handler.
  640. * This method is the opposite of {@link attachEventHandler}.
  641. * @param {String} name event name
  642. * @param {Yii.Callback} handler the event handler to be removed
  643. * @returns {Boolean} if the detachment process is successful
  644. * @see attachEventHandler
  645. */
  646. Yii.CComponent.prototype.detachEventHandler = function (name, handler) {
  647. if(this.hasEventHandler(name)) {
  648. return this.getEventHandlers(name).remove(handler)!==false;
  649. }
  650. else {
  651. return false;
  652. }
  653. };
  654. /**
  655. * Raises an event.
  656. * This method represents the happening of an event. It invokes
  657. * all attached handlers for the event.
  658. * @param {String} name the event name
  659. * @param {Yii.CEvent} event the event parameter
  660. * @throws {Yii.CException} if the event is undefined or an event handler is invalid.
  661. */
  662. Yii.CComponent.prototype.raiseEvent = function (name, event) {
  663. var i, handler, object, method, limit;
  664. if(this._e !== null && this._e[name] !== undefined) {
  665. limit = this._e[name].length;
  666. for (i = 0; i < limit; i++) {
  667. handler = this._e[name][i];
  668. if(typeof(handler) === 'string') {
  669. php.call_user_func(handler,event);
  670. }
  671. if(Object.prototype.toString.call(handler) === '[object Array]') {
  672. // an array: 0 - object, 1 - method name
  673. object = handler[0];
  674. method = handler[1];
  675. if(typeof(object) === 'string') { // static method call
  676. php.call_user_func(handler,event);
  677. }
  678. else if(php.method_exists(object,method)) {
  679. object[method](event);
  680. }
  681. else {
  682. throw new Yii.CException(Yii.t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',
  683. {'{class}':this.getClassName(), '{event}':name, '{handler}':handler[1]}));
  684. }
  685. }
  686. else if (typeof handler === "function") { // callback function
  687. php.call_user_func(handler,event);
  688. }
  689. else {
  690. console.log(i);
  691. console.log(name);
  692. console.log(handler);
  693. throw new Yii.CException(Yii.t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',
  694. {'{class}':this.getClassName(), '{event}':name, '{handler}':handler}));
  695. }
  696. // stop further handling if param.handled is set true
  697. if((event instanceof Yii.CEvent) && event.handled) {
  698. return;
  699. }
  700. }
  701. }
  702. else if(YII_DEBUG && !this.hasEvent(name)) {
  703. throw new Yii.CException(Yii.t('yii','Event "{class}.{event}" is not defined.',
  704. {'{class}':this.getClassName(), '{event}':name}));
  705. }
  706. };
  707. /**
  708. * Evaluates a PHP expression or callback under the context of this component.
  709. *
  710. * Valid PHP callback can be class method name in the form of
  711. * array(ClassName/Object, MethodName), or anonymous function (only available in PHP 5.3.0 or above).
  712. *
  713. * If a PHP callback is used, the corresponding function/method signature should be
  714. * <pre>
  715. * function foo(param1, param2, +++, component) { +++ }
  716. * </pre>
  717. * where the array elements in the second parameter to this method will be passed
  718. * to the callback as $param1, $param2, ...; and the last parameter will be the component itself.
  719. *
  720. * If a PHP expression is used, the second parameter will be "extracted" into PHP variables
  721. * that can be directly accessed in the expression. See {@link http://us.php.net/manual/en/function.extract.php PHP extract}
  722. * for more details. In the expression, the component object can be accessed using $this.
  723. *
  724. * @param {Mixed} _expression_ a PHP expression or PHP callback to be evaluated.
  725. * @param {Array} _data_ additional parameters to be passed to the above expression/callback.
  726. * @returns {Mixed} the expression result
  727. * @since 1.1.0
  728. */
  729. Yii.CComponent.prototype.evaluateExpression = function (_expression_, _data_) {
  730. if (_data_ === undefined) {
  731. _data_ = [];
  732. }
  733. if(typeof(_expression_) === 'string')
  734. {
  735. php.extract(_data_);
  736. return eval('return '+_expression_+';');
  737. }
  738. else
  739. {
  740. _data_.push(this);
  741. return php.call_user_func_array(_expression_, _data_);
  742. }
  743. }