| @@ -47,8 +47,15 @@ | ||
| 47 | 47 | * put your comment there... |
| 48 | 48 | * |
| 49 | 49 | * @var mixed |
| 50 | 50 | */ |
| 51 | + protected static $instance = null; | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * put your comment there... | |
| 55 | + * | |
| 56 | + * @var mixed | |
| 57 | + */ | |
| 51 | 58 | private $onActionIds = array(); |
| 52 | 59 | |
| 53 | 60 | /** |
| 54 | 61 | * put your comment there... |
| @@ -62,11 +69,18 @@ | ||
| 62 | 69 | * |
| 63 | 70 | * @var mixed |
| 64 | 71 | */ |
| 65 | 72 | protected $onappendcode = array('parameters' => array('code')); |
| 66 | - | |
| 73 | + | |
| 67 | 74 | /** |
| 68 | 75 | * put your comment there... |
| 76 | + * | |
| 77 | + * @var mixed | |
| 78 | + */ | |
| 79 | + protected $onblockmatched = array('parameters' => array('block')); | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * put your comment there... | |
| 69 | 83 | * |
| 70 | 84 | * @var mixed |
| 71 | 85 | */ |
| 72 | 86 | protected $oncancelmatching = array('parameters' => array('matched')); |
| @@ -111,8 +125,15 @@ | ||
| 111 | 125 | * |
| 112 | 126 | * @var mixed |
| 113 | 127 | */ |
| 114 | 128 | protected $ongetfilters = array('parameters' => array('filters')); |
| 129 | + | |
| 130 | + /** | |
| 131 | + * put your comment there... | |
| 132 | + * | |
| 133 | + * @var mixed | |
| 134 | + */ | |
| 135 | + protected $onlinkedtemplates = array('parameters' => array('templates')); | |
| 115 | 136 | |
| 116 | 137 | /** |
| 117 | 138 | * put your comment there... |
| 118 | 139 | * |
| @@ -117,8 +138,29 @@ | ||
| 117 | 138 | * put your comment there... |
| 118 | 139 | * |
| 119 | 140 | * @var mixed |
| 120 | 141 | */ |
| 142 | + protected $onlinkscripts = array('parameters' => array('templates')); | |
| 143 | + | |
| 144 | + /** | |
| 145 | + * put your comment there... | |
| 146 | + * | |
| 147 | + * @var mixed | |
| 148 | + */ | |
| 149 | + protected $onlinkstyles = array('parameters' => array('templates')); | |
| 150 | + | |
| 151 | + /** | |
| 152 | + * put your comment there... | |
| 153 | + * | |
| 154 | + * @var mixed | |
| 155 | + */ | |
| 156 | + protected $onlinktemplate = array('parameters' => array('template')); | |
| 157 | + | |
| 158 | + /** | |
| 159 | + * put your comment there... | |
| 160 | + * | |
| 161 | + * @var mixed | |
| 162 | + */ | |
| 121 | 163 | protected $onmatchingurls = array('parameters' => array('urls')); |
| 122 | 164 | |
| 123 | 165 | /** |
| 124 | 166 | * put your comment there... |
| @@ -152,11 +194,32 @@ | ||
| 152 | 194 | * put your comment there... |
| 153 | 195 | * |
| 154 | 196 | * @var mixed |
| 155 | 197 | */ |
| 198 | + protected $onqueuecss = array('parameters' => array('style')); | |
| 199 | + | |
| 200 | + /** | |
| 201 | + * put your comment there... | |
| 202 | + * | |
| 203 | + * @var mixed | |
| 204 | + */ | |
| 205 | + protected $onqueuejavascript = array('parameters' => array('script')); | |
| 206 | + | |
| 207 | + /** | |
| 208 | + * put your comment there... | |
| 209 | + * | |
| 210 | + * @var mixed | |
| 211 | + */ | |
| 156 | 212 | protected $onsetfilters = array('parameters' => array('filters')); |
| 157 | 213 | |
| 158 | 214 | /** |
| 215 | + * put your comment there... | |
| 216 | + * | |
| 217 | + * @var mixed | |
| 218 | + */ | |
| 219 | + protected $templates = array(); | |
| 220 | + | |
| 221 | + /** | |
| 159 | 222 | * Initialize controller object. |
| 160 | 223 | * |
| 161 | 224 | * @see CJTController for more details |
| 162 | 225 | * @return void |
| @@ -161,8 +224,15 @@ | ||
| 161 | 224 | * @see CJTController for more details |
| 162 | 225 | * @return void |
| 163 | 226 | */ |
| 164 | 227 | public function __construct() { |
| 228 | + // Only one instance is allowed. | |
| 229 | + if (self::$instance) { | |
| 230 | + throw new Exception('Trying to instantiate multiple coupling instances!!'); | |
| 231 | + } | |
| 232 | + // Hold the single instance we've! | |
| 233 | + self::$instance = $this; | |
| 234 | + $siteHook = cssJSToolbox::$config->core->siteHook; | |
| 165 | 235 | // Initialize controller. |
| 166 | 236 | parent::__construct(false); |
| 167 | 237 | // Import related libraries |
| 168 | 238 | CJTModel::import('block'); |
| @@ -170,9 +240,9 @@ | ||
| 170 | 240 | $this->defaultAction = null; |
| 171 | 241 | // Initialize controller. |
| 172 | 242 | $initCouplingCallback = $this->onassigncouplingcallback(array(&$this, 'initCoupling')); |
| 173 | 243 | add_action('admin_init', $initCouplingCallback); |
| 174 | - add_action('wp', $initCouplingCallback); | |
| 244 | + add_action($siteHook->tag, $initCouplingCallback, $siteHook->priority); | |
| 175 | 245 | // Add Shortcode callbacks. |
| 176 | 246 | add_shortcode('cjtoolbox', array(&$this, 'shortcode')); |
| 177 | 247 | } |
| 178 | 248 | |
| @@ -178,9 +248,23 @@ | ||
| 178 | 248 | |
| 179 | 249 | /** |
| 180 | 250 | * put your comment there... |
| 181 | 251 | * |
| 252 | + * @param mixed $id | |
| 182 | 253 | */ |
| 254 | + public function addOnActionIds($id) { | |
| 255 | + // Add ID is not exists. | |
| 256 | + if (!in_array($id, $this->onActionIds)) { | |
| 257 | + $this->onActionIds[] = $id; | |
| 258 | + } | |
| 259 | + // Chaining. | |
| 260 | + return $this; | |
| 261 | + } | |
| 262 | + | |
| 263 | + /** | |
| 264 | + * put your comment there... | |
| 265 | + * | |
| 266 | + */ | |
| 183 | 267 | public function getBlocks() { |
| 184 | 268 | // Set request view filters used for querying database. |
| 185 | 269 | $this->setRequestFilters(); |
| 186 | 270 | // Get blocks order. NOTE: This is all blocks order not only the queried/target blocks. |
| @@ -187,8 +271,13 @@ | ||
| 187 | 271 | $blocksOrder = array(); |
| 188 | 272 | $metaBoxesOrder = $this->onblocksorder($this->model->getOrder()); |
| 189 | 273 | // Get ORDER-INDEX <TO> BLOCK-ID mapping. |
| 190 | 274 | preg_match_all('/cjtoolbox-(\d+)/', $metaBoxesOrder['normal'], $blocksOrder, PREG_SET_ORDER); |
| 275 | + /** | |
| 276 | + * append more to orders produced by CJTBlocksCouplingController::setRequestFilter(). | |
| 277 | + * More to orders may allow other blocks to bein the output (e.g metaboxe blocks). | |
| 278 | + */ | |
| 279 | + $blocksOrder = array_merge($blocksOrder, $this->getFilters()->moreToOrder); | |
| 191 | 280 | // Prepare request URL to match against Links & Expressions. |
| 192 | 281 | $linksRequestURL = self::getRequestURL(); |
| 193 | 282 | $expressionsRequestURL = "{$linksRequestURL}?{$_SERVER['QUERY_STRING']}"; |
| 194 | 283 | extract($this->onmatchingurls(compact('linksRequestURL', 'expressionsRequestURL'))); |
| @@ -235,12 +324,8 @@ | ||
| 235 | 324 | /// @TODO: Matches may be used later to evaulate variables inside code block. |
| 236 | 325 | if($matchedExpression = @preg_match("/{$expression}/", $expressionsRequestURL)) { |
| 237 | 326 | break; |
| 238 | 327 | } |
| 239 | - else if ($matchedExpression === false) { // Error | |
| 240 | - $message .= "<div style='background-color:red;font-size:20px;'>There are expression error in '{$block->name}' Block!! Expr=({$expression})</div>"; | |
| 241 | - echo($message); | |
| 242 | - } | |
| 243 | 328 | } |
| 244 | 329 | } |
| 245 | 330 | /** |
| 246 | 331 | * Exclude Links & Expressions Blocks that doesn't has a match. |
| @@ -249,20 +334,33 @@ | ||
| 249 | 334 | if ($this->oncancelmatching(!($matchedExpression || $matchedLink))) { |
| 250 | 335 | continue; |
| 251 | 336 | } |
| 252 | 337 | } |
| 253 | - // For every location store blocks code into single string | |
| 254 | - /** @todo Use method other data:// wrapper, its only available in Hight version of PHP (5.3 or so!) */ | |
| 255 | - $evaluatedCode = CJTPHPCodeEvaluator::getInstance($block)->exec()->getOutput(); | |
| 256 | - /** @todo Include Debuging info only if we're in debuging mode! */ | |
| 257 | - if (1) { | |
| 258 | - $evaluatedCode = "\n<!-- Block ({$blockId}) START-->\n{$evaluatedCode}\n<!-- Block ({$blockId}) END -->\n"; | |
| 338 | + // Allow extensions to control to prevent block from being in the output | |
| 339 | + if ($block = $this->onblockmatched($block)) { | |
| 340 | + // Retrieve block code-files. | |
| 341 | + $block->code = $this->model->getBlockCode($block->id); | |
| 342 | + // Import Executable (PHP and HTML) templates. | |
| 343 | + $block->code = $block->code . $this->model->getExecTemplatesCode($block->id); | |
| 344 | + // For every location store blocks code into single string | |
| 345 | + $evaluatedCode = CJTPHPCodeEvaluator::getInstance($block)->exec()->getOutput(); | |
| 346 | + /** @todo Include Debuging info only if we're in debuging mode! */ | |
| 347 | + if (1) { | |
| 348 | + $evaluatedCode = "\n<!-- Block ({$blockId}) START-->\n{$evaluatedCode}\n<!-- Block ({$blockId}) END -->\n"; | |
| 349 | + } | |
| 350 | + $this->blocks['code'][$block->location] .= $this->onappendcode($evaluatedCode); | |
| 351 | + // Store all used Ids in the CORRECT ORDER. | |
| 352 | + $this->addOnActionIds($blockId); | |
| 259 | 353 | } |
| 260 | - $this->blocks['code'][$block->location] .= $this->onappendcode($evaluatedCode); | |
| 261 | - // Store all used Ids in the CORRECT ORDER. | |
| 262 | - $this->onActionIds[] = $blockId; | |
| 263 | 354 | } |
| 264 | 355 | } |
| 356 | + $templates = $this->onActionIds ? $this->model->getLinkedTemplates($this->onActionIds) : array(); | |
| 357 | + // Classisfy as we process Scripts and Styles separatly (different hooks!). | |
| 358 | + foreach ($this->onlinkedtemplates($templates) as $id => $template) { | |
| 359 | + // Filer template! | |
| 360 | + extract($this->onlinktemplate(compact('template', 'id'))); | |
| 361 | + $this->templates[$template->type][$id] = $template; | |
| 362 | + } | |
| 265 | 363 | // Return true if there is at least 1 block return within the set. |
| 266 | 364 | return true; |
| 267 | 365 | } |
| 268 | 366 | |
| @@ -281,13 +379,21 @@ | ||
| 281 | 379 | */ |
| 282 | 380 | public function getFilters() { |
| 283 | 381 | return $this->ongetfilters($this->filters); |
| 284 | 382 | } |
| 285 | - | |
| 383 | + | |
| 286 | 384 | /** |
| 287 | 385 | * put your comment there... |
| 288 | 386 | * |
| 289 | 387 | */ |
| 388 | + public function getOnActionIds() { | |
| 389 | + return $this->onActionIds; | |
| 390 | + } | |
| 391 | + | |
| 392 | + /** | |
| 393 | + * put your comment there... | |
| 394 | + * | |
| 395 | + */ | |
| 290 | 396 | public static function getRequestURL() { |
| 291 | 397 | // URL Protocol. |
| 292 | 398 | $protocol = 'http' . ((isset($_SERVER["HTTPS"]) && ($_SERVER["HTTPS"] == "on")) ? 's' : '') . '://'; |
| 293 | 399 | // Host name & port. |
| @@ -303,8 +409,16 @@ | ||
| 303 | 409 | /** |
| 304 | 410 | * put your comment there... |
| 305 | 411 | * |
| 306 | 412 | */ |
| 413 | + public function hasOnActionIds() { | |
| 414 | + return !empty($this->onActionIds); | |
| 415 | + } | |
| 416 | + | |
| 417 | + /** | |
| 418 | + * put your comment there... | |
| 419 | + * | |
| 420 | + */ | |
| 307 | 421 | public function initCoupling() { |
| 308 | 422 | // For some reasons wp action is fired twice. |
| 309 | 423 | // The wrong call won't has $wp_query object set, |
| 310 | 424 | // but this is only valid at Front end. |
| @@ -310,17 +424,23 @@ | ||
| 310 | 424 | // but this is only valid at Front end. |
| 311 | 425 | if (!is_admin() && !$GLOBALS['wp_query']) { |
| 312 | 426 | return; |
| 313 | 427 | } |
| 428 | + // Get current application hook prefix. | |
| 429 | + $actionsPrefix = is_admin() ? 'admin' : 'wp'; | |
| 314 | 430 | // Get cache or get blocks if not cached. |
| 315 | 431 | // If there is no cache or no blocks for output |
| 316 | 432 | // do nothing. |
| 317 | 433 | if ($this->getCached() || $this->getBlocks()) { |
| 318 | - $actionsPrefix = is_admin() ? 'admin' : 'wp'; | |
| 319 | 434 | // Output blocks on various locations! |
| 320 | 435 | add_action("{$actionsPrefix}_head", array(&$this, 'outputBlocks'), 30); |
| 321 | 436 | add_action("{$actionsPrefix}_footer", array(&$this, 'outputBlocks'), 30); |
| 437 | + // Links templates & styloes! | |
| 438 | + add_action("{$actionsPrefix}_enqueue_scripts", array(&$this, 'linkTemplates'), 30); | |
| 439 | + add_action("{$actionsPrefix}_print_styles", array(&$this, 'linkTemplates'), 30); | |
| 322 | 440 | } |
| 441 | + // Link style sheet in footer required custom implementation. | |
| 442 | + add_action("{$actionsPrefix}_print_footer_scripts", array(&$this, 'linkFooterStyleSheets'), 9); | |
| 323 | 443 | // Make sure this is executed only once. |
| 324 | 444 | // Sometimes wp hook run on backend and sometimes its not. |
| 325 | 445 | // This method handle both front and backend requests. |
| 326 | 446 | // Simply remove all hooks to ensure its run only one time. |
| @@ -331,8 +451,71 @@ | ||
| 331 | 451 | /** |
| 332 | 452 | * put your comment there... |
| 333 | 453 | * |
| 334 | 454 | */ |
| 455 | + public function linkFooterStyleSheets() { | |
| 456 | + // Initialize. | |
| 457 | + $styles = array(); | |
| 458 | + // Get queued style sheets! | |
| 459 | + global $wp_styles; | |
| 460 | + $queuedStyles =& $wp_styles->queue; | |
| 461 | + // Process only 'cjt' templates, | |
| 462 | + foreach ($queuedStyles as $index => $styleName) { | |
| 463 | + if (strpos($styleName, 'cjt-css-template-') === 0) { | |
| 464 | + // Get style name src file, prepend to Wordpress absolute path. | |
| 465 | + $style = $wp_styles->registered[$styleName]; | |
| 466 | + $styles[] = home_url($style->src); | |
| 467 | + // Stop Wordpress from output <link> tag outside head tag | |
| 468 | + // as it has no effect. | |
| 469 | + unset($queuedStyles[$index]); | |
| 470 | + } | |
| 471 | + } | |
| 472 | + // Enqueue Style Sheet loader javascript if there is any | |
| 473 | + // styles need to be loaded. | |
| 474 | + if (!empty($styles)) { | |
| 475 | + // jQuery is dpendency object required by the loader. | |
| 476 | + wp_enqueue_script('jquery'); | |
| 477 | + // Enqueue footer style sheet loader. | |
| 478 | + wp_enqueue_script('cjt-coupling-footer-css-loader', cssJSToolbox::getURI('controllers:coupling:js:footer-stylesheet-loader.js')); | |
| 479 | + // Output Javascript array to be filled with the styles! | |
| 480 | + $jsStyleSheetsList = json_encode($styles); | |
| 481 | + require cssJSToolbox::resolvePath('controllers:coupling:html:load-footer-style.html.php'); | |
| 482 | + } | |
| 483 | + } | |
| 484 | + | |
| 485 | + /** | |
| 486 | + * put your comment there... | |
| 487 | + * | |
| 488 | + */ | |
| 489 | + public function linkTemplates() { | |
| 490 | + $currentFilter = current_filter(); | |
| 491 | + // Derived template Type from Wordpress filter. | |
| 492 | + $filterFor = explode('_', $currentFilter); $filterFor = array_pop($filterFor); | |
| 493 | + $type = CJTCouplingModel::$templateTypes[$filterFor]; | |
| 494 | + // Following vars are referenced based on the current type. | |
| 495 | + $templates = isset($this->templates[$type]) ? $this->templates[$type] : array(); | |
| 496 | + // Filering! | |
| 497 | + $templates = $this->{"onlink{$filterFor}"}($templates); | |
| 498 | + /** | |
| 499 | + * @var WP_Dependencies | |
| 500 | + */ | |
| 501 | + $queue = $this->model->getQueueObject($filterFor); | |
| 502 | + // Add templates to the queye. | |
| 503 | + foreach ($templates as $template) { | |
| 504 | + // Registery only if not yet registered. | |
| 505 | + $template = $this->{"onqueue{$type}"}($template); | |
| 506 | + if (!isset($queue->registered[$template->queueName])) { | |
| 507 | + $queue->add($template->queueName, "/{$template->file}", null, $template->version); | |
| 508 | + } | |
| 509 | + // Always make sure the template is queued. | |
| 510 | + $queue->enqueue($template->queueName); | |
| 511 | + } | |
| 512 | + } | |
| 513 | + | |
| 514 | + /** | |
| 515 | + * put your comment there... | |
| 516 | + * | |
| 517 | + */ | |
| 335 | 518 | public function outputBlocks() { |
| 336 | 519 | // Derived location name from wordpress filter name. |
| 337 | 520 | $currentFilter = current_filter(); |
| 338 | 521 | // Map "wp hook location" to "block hook location". |
| @@ -354,8 +537,9 @@ | ||
| 354 | 537 | // Get request blocks. |
| 355 | 538 | $filters = $this->ondefaultfilters((object) array( |
| 356 | 539 | 'pinPoint' => 0x00000000, |
| 357 | 540 | 'customPins' => array(), |
| 541 | + 'moreToOrder' => array(), | |
| 358 | 542 | )); |
| 359 | 543 | if (is_admin()) { |
| 360 | 544 | // Include all backend blocks. |
| 361 | 545 | $filters->pinPoint |= CJTBlockModel::PINS_BACKEND; |
| @@ -375,8 +559,15 @@ | ||
| 375 | 559 | // Blocks with FRONT-PAGE selected. |
| 376 | 560 | if (is_front_page()) { |
| 377 | 561 | $filters->pinPoint |= CJTBlockModel::PINS_PAGES_FRONT_PAGE; |
| 378 | 562 | } |
| 563 | + /** | |
| 564 | + * In order for metabox block to get in the output we need | |
| 565 | + * to add metabox order for it. | |
| 566 | + * @see CJTBlocksCouplingController::getBlocks. | |
| 567 | + */ | |
| 568 | + $metabox = CJTModel::create('metabox', array($GLOBALS['post']->ID)); | |
| 569 | + $filters->moreToOrder[][1] = $metabox->getMetaboxId(); | |
| 379 | 570 | } // End is_page() |
| 380 | 571 | else if (is_attachment()) { |
| 381 | 572 | $filters->pinPoint |= CJTBlockModel::PINS_ATTACHMENT; |
| 382 | 573 | } |
| @@ -405,8 +596,15 @@ | ||
| 405 | 596 | 'pins' => $parentCategoriesIds, |
| 406 | 597 | 'flag' => CJTBlockModel::PINS_CATEGORIES_CUSTOM_CATEGORY, |
| 407 | 598 | ); |
| 408 | 599 | } |
| 600 | + /** | |
| 601 | + * In order for metabox block to get in the output we need | |
| 602 | + * to add metabox order for it. | |
| 603 | + * @see CJTBlocksCouplingController::getBlocks. | |
| 604 | + */ | |
| 605 | + $metabox = CJTModel::create('metabox', array($GLOBALS['post']->ID)); | |
| 606 | + $filters->moreToOrder[][1] = $metabox->getMetaboxId(); | |
| 409 | 607 | /** |
| 410 | 608 | * @TODO check for recent posts Based on user configuration. |
| 411 | 609 | * Recent posts should be detcted by comparing |
| 412 | 610 | * user condifguration with post date. |
| @@ -449,53 +647,33 @@ | ||
| 449 | 647 | $this->filters = $this->onsetfilters($filters); |
| 450 | 648 | } |
| 451 | 649 | |
| 452 | 650 | /** |
| 651 | + * Wordpress do shortcode callback for | |
| 652 | + * CJT Shortcodes ([cjtoolbox ....])! | |
| 653 | + * | |
| 654 | + * This method role is to load the shortcode routines | |
| 655 | + * in order to handle the request. | |
| 656 | + * | |
| 657 | + * It doesn't do anything except deferring the shortcode | |
| 658 | + * codes from loaded until shortcode is really used! | |
| 659 | + * | |
| 660 | + * @param mixed $attributes | |
| 661 | + */ | |
| 662 | + public function shortcode($attributes, $content) { | |
| 663 | + // Instantiate Shortcode handler class. | |
| 664 | + cssJSToolbox::import('controllers:coupling:shortcode:shortcode.php'); | |
| 665 | + $shortcode = new CJT_Controllers_Coupling_Shortcode($attributes, $content); | |
| 666 | + // Return Shortcode replacement! | |
| 667 | + return ((string) $shortcode); | |
| 668 | + } | |
| 669 | + | |
| 670 | + /** | |
| 453 | 671 | * put your comment there... |
| 454 | 672 | * |
| 455 | - * @param mixed $attributes | |
| 456 | 673 | */ |
| 457 | - public function shortcode($attributes) { | |
| 458 | - // Initialize vars. | |
| 459 | - $replacement = ''; | |
| 460 | - // Default Class. | |
| 461 | - if (!$attributes['class']) { | |
| 462 | - $class = 'block'; | |
| 463 | - } | |
| 464 | - switch ($class) { | |
| 465 | - case 'block': | |
| 466 | - // Get is the default "operation"! | |
| 467 | - if (!$attributes['op']) { | |
| 468 | - $attributes['op'] = 'get'; | |
| 469 | - } | |
| 470 | - switch ($attributes['op']) { | |
| 471 | - case 'get': | |
| 472 | - // Import dependecies. | |
| 473 | - cssJSToolbox::import('framework:db:mysql:xtable.inc.php'); | |
| 474 | - // Output block if 'force="true" or only if it wasn't already in the header/footer! | |
| 475 | - if ((($attributes['force'] == "true") || !in_array($attributes['id'], $this->onActionIds))) { | |
| 476 | - // Id is being used! | |
| 477 | - if ($attributes['force'] != 'true') { | |
| 478 | - $this->onActionIds[] = (int) $attributes['id']; | |
| 479 | - } | |
| 480 | - // Get block code. | |
| 481 | - $block = CJTxTable::getInstance('block') | |
| 482 | - ->set('id', $attributes['id']) | |
| 483 | - ->load(); | |
| 484 | - // Only ACTIVE blocks! | |
| 485 | - if ($block->get('state') != 'active') { | |
| 486 | - return; | |
| 487 | - } | |
| 488 | - $replacement = $block->get('code'); | |
| 489 | - } | |
| 490 | - break; | |
| 491 | - } | |
| 492 | - break; | |
| 493 | - default: | |
| 494 | - $replacement = cssJSToolbox::getText('Shortcode Type is not supported!! Only (block) type is currently available!!!'); | |
| 495 | - break; | |
| 496 | - } | |
| 497 | - return $replacement; | |
| 674 | + public static function & theInstance() { | |
| 675 | + return self::$instance; | |
| 498 | 676 | } |
| 499 | 677 | |
| 500 | 678 | } // End class. |
| 501 | 679 | |