Source for file block-defs.php

Documentation is available at block-defs.php

  1. <?php
  2. /* ******************************************************************** */
  3. /* CATALYST PHP Source Code */
  4. /* -------------------------------------------------------------------- */
  5. /* This program is free software; you can redistribute it and/or modify */
  6. /* it under the terms of the GNU General Public License as published by */
  7. /* the Free Software Foundation; either version 2 of the License, or */
  8. /* (at your option) any later version. */
  9. /* */
  10. /* This program is distributed in the hope that it will be useful, */
  11. /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
  12. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
  13. /* GNU General Public License for more details. */
  14. /* */
  15. /* You should have received a copy of the GNU General Public License */
  16. /* along with this program; if not, write to: */
  17. /* The Free Software Foundation, Inc., 59 Temple Place, Suite 330, */
  18. /* Boston, MA 02111-1307 USA */
  19. /* -------------------------------------------------------------------- */
  20. /* */
  21. /* Filename: block-defs.php */
  22. /* Author: Paul Waite */
  23. /* Description: Definitions for content block management in webpages. */
  24. /* */
  25. /* ******************************************************************** */
  26. /** @package cm */
  27. include_once("form-defs.php");
  28.  
  29. // ......................................................................
  30. // DEFINITIONS
  31.  
  32. /** Identity value signifying new block
  33. @access private */
  34. define("NEW_BLOCK", -1);
  35. /** Identity value signifying new blocklet
  36. @access private */
  37. define("NEW_BLOCKLET", -1);
  38.  
  39. /** Block/layout version undefined
  40. @access private */
  41. define("VERSION_UNDEFINED", -1);
  42. /** Block/layout version is pending
  43. @access private */
  44. define("VERSION_PENDING", 0);
  45. /** Block/layout version is live
  46. @access private */
  47. define("VERSION_LIVE", 1);
  48. /** Block/layout version is previous
  49. @access private */
  50. define("VERSION_PREVIOUS", 2);
  51.  
  52. /** Layout cell content: empty
  53. @access private */
  54. define("EMPTY_CELL", "" );
  55. /** Layout cell content: standard block
  56. @access private */
  57. define("BLOCK_CONTENT", "b");
  58. /** Layout cell content: HTMLArea wysiwyg editor
  59. @access private */
  60. define("WYSIWYG_EDITOR", "w");
  61. /** Layout cell content: plain cell
  62. @access private */
  63. define("PLAIN_CELL", "p");
  64.  
  65. /** Default Editor group membership */
  66. ("DEFAULT_EDITOR_GROUPS", "Editor");
  67. /** Default Author group membership */
  68. ("DEFAULT_AUTHOR_GROUPS", "Author");
  69. /** Default Entry group membership */
  70. ("DEFAULT_ENTRY_GROUPS", "Entry");
  71.  
  72. // ......................................................................
  73. /**
  74. * Block
  75. * We define a class called a 'block'. This can contain multiple
  76. * 'blocklet' elements which fill up a block top-to-bottom. A block
  77. * can be divided into multiple columns, and blocklets fill these
  78. * left-to-right.
  79. * Blocklets can be of several defined blocklet_types:
  80. * Text, List, Ordered list, Bullets, and Table
  81. * A blocklet can also have a heading and a ruler defined for it,
  82. * with various formatting properties. Provision is also made for
  83. * inserting special 'tags' into the blocklet content which are
  84. * translated by the system accordingly. These are:
  85. * Data - tags to access database information
  86. * Images - reference to a resident image
  87. * Links - A clickable link (url)
  88. * Doc links - A link to a resident document file
  89. * @package cm
  90. */
  91. class block extends RenderableObject {
  92. // Public
  93. /** Whether the block exists in database or not */
  94.  
  95. var $exists = false;
  96. /** The id of the current block */
  97.  
  98. var $blockid = 0;
  99. /** The description of the current block */
  100.  
  101. var $block_desc = "";
  102. /** The language of the block (0 = default) */
  103.  
  104. var $language = 0;
  105. /** The language encoding code */
  106.  
  107. var $lang_encoding = "";
  108. /** The language text direction */
  109.  
  110. var $lang_direction = "";
  111. /** The number of columns in this block */
  112.  
  113. var $cols = 1;
  114. /** Width of inter-column gutter in pixels */
  115.  
  116. var $gutter_width = 0;
  117. /** Colour of inter-column gutter */
  118.  
  119. var $gutter_colour = "";
  120. /** Vertical separation of blocklets in pixels */
  121.  
  122. var $blocklet_sep = 0;
  123. /** Width of border in pixels */
  124.  
  125. var $border_width = 0;
  126. /** Colour of border */
  127.  
  128. var $border_colour = "";
  129. /** Colour of block background */
  130.  
  131. var $background_colour = "";
  132. /** Background image - ID from ax_catalog table, if defined */
  133.  
  134. var $background_img = NULLVALUE;
  135. /** Justification: 'left', 'center', 'right' */
  136.  
  137. var $justify = "";
  138. /** Vertical alignment: 'top', 'middle', 'bottom' */
  139.  
  140. var $valign = "";
  141. /** Manual style entered by user */
  142.  
  143. var $block_style = "";
  144. /** If true, then an EXPORT button will be provided for CSV dump */
  145.  
  146. var $exportable = false;
  147. /** Array of blocklet objects in this block */
  148.  
  149. var $blocklets = array();
  150. /** The layout this block belongs to */
  151.  
  152. var $layoutid;
  153. /** Version of layout this block belongs to (optional). If present
  154. then the version is included in forms as a hidden field. */
  155. var $layout_version = VERSION_UNDEFINED;
  156. /** Count of layout versions in existence. */
  157.  
  158. var $layout_version_count = 0;
  159. /** The language encoding for the containing layout */
  160.  
  161. var $layout_lang_encoding = "";
  162. /** The language direction for the containing layout */
  163.  
  164. var $layout_lang_direction = "";
  165. /** Type of block, ""=empty, "b"=block content, "w"=wysiwyg, "p"=plain cell */
  166.  
  167. var $block_type = "";
  168.  
  169. // Private
  170. /** The form name for the current block @access private */
  171.  
  172. var $blockfm = "";
  173. /** Mode of operation, 'viewing', 'editing', 'saving' @access private */
  174.  
  175. var $mode = "viewing";
  176. /** The group membership for Editor privilege
  177. @access private */
  178. var $editor_groups = array(DEFAULT_EDITOR_GROUPS);
  179. /** The group membership for Authoring privilege
  180. @access private */
  181. var $author_groups = array(DEFAULT_AUTHOR_GROUPS);
  182. /** The group membership for Entry privilege
  183. @access private */
  184. var $entry_groups = array(DEFAULT_ENTRY_GROUPS);
  185. // ....................................................................
  186. /**
  187. * Constructor
  188. * Create a new block object.
  189. * Blocks are self-contained entities, and so this constructor is written
  190. * to return the rendered block content. This just allows you to avoid
  191. * having to make the render() call, and use the constructor to return
  192. * the block content in one hit.
  193. * @param string $id The unique name/identity of the block.
  194. * $return string The block content, whatever that may be.
  195. */
  196. function block($id=NEW_BLOCK) {
  197. // Deal with new block requirement..
  198. if ($id == NEW_BLOCK) {
  199. $id = get_next_sequencevalue("seq_block_id", "ax_block", "block_id");
  200. }
  201.  
  202. // Save block ID..
  203. $this->blockid = $id;
  204.  
  205. // Define a unique form name..
  206. $this->blockfm = "blockfm_$id";
  207.  
  208. // Process anything POSTed via form..
  209. $this->POSTprocess();
  210.  
  211. // Read it all from disk
  212. $this->get($id);
  213.  
  214. } // block
  215. // ....................................................................
  216. /**
  217. * Provide a blockeditor. This is used to instantiate a blockeditor
  218. * object for when we need to change this block somewhow. We only
  219. * need one, so we check if it's already been done first.
  220. */
  221. function activate_editing() {
  222. if (!isset($this->blockeditor)) {
  223. global $RESPONSE, $LIBDIR;
  224. include_once("block-editor-defs.php");
  225. $this->blockeditor = new blockeditor($this);
  226. }
  227. } // activate_editing
  228. // ....................................................................
  229. /**
  230. * Set the layout info for the layout which contains this block. If
  231. * defined the version is included in the block edit form as a hidden
  232. * field so that the layout can be kept across block form submission.
  233. * Both bits of data are also used to determine what happens regarding
  234. * for example indexing saved block content etc.
  235. * @param string $lver The version of the layout containing this block
  236. * @param integer $vercount The # versions of the layout
  237. * @param integer $lang The language ID of the layout
  238. * @param string $lang_enc The language encoding of the layout
  239. * @param string $lang_dir The language direction of the layout
  240. * @access private
  241. */
  242. function set_layout_info(
  243. $ver=VERSION_UNDEFINED,
  244. $vercount=0,
  245. $lang=0,
  246. $lang_enc="",
  247. $lang_dir="",
  248. $editor_groups=DEFAULT_EDITOR_GROUPS,
  249. $author_groups=DEFAULT_AUTHOR_GROUPS,
  250. $entry_groups=DEFAULT_ENTRY_GROUPS
  251. ) {
  252. $this->layout_version = $ver;
  253. $this->layout_version_count = $vercount;
  254. $this->layout_language = $lang;
  255. $this->layout_lang_encoding = $lang_enc;
  256. $this->layout_lang_direction = $lang_dir;
  257. $this->editor_groups = $editor_groups;
  258. $this->author_groups = $author_groups;
  259. $this->entry_groups = $entry_groups;
  260. } // set_layout_info
  261. // ....................................................................
  262. /**
  263. * Return true if the current user is permitted to edit block details.
  264. * We allow editing only for versions VERSION_PENDING and VERSION_LIVE
  265. * and the latter only for Editors.
  266. * @return boolean True if editing is permitted by current user.
  267. */
  268. function user_can_edit($required_version=VERSION_UNDEFINED) {
  269. global $RESPONSE;
  270. if ($this->layout_version == VERSION_UNDEFINED) {
  271. return true;
  272. }
  273. $perm = false;
  274. if ($required_version == VERSION_UNDEFINED ||
  275. $required_version == $this->layout_version) {
  276. // Pending version
  277. if ($this->layout_version == VERSION_PENDING ||
  278. $this->layout_version_count == 1) {
  279. if ($RESPONSE->ismemberof_group_in( array_merge($this->editor_groups, $this->author_groups) )) {
  280. $perm = true;
  281. }
  282. }
  283. // Live version
  284. elseif ($this->layout_version == VERSION_LIVE) {
  285. if ($RESPONSE->ismemberof_group_in( $this->editor_groups )) {
  286. $perm = true;
  287. }
  288. }
  289. }
  290. return $perm;
  291. } // user_can_edit
  292. // ....................................................................
  293. /**
  294. * Get the block.
  295. * Retrieves the specified block from database.
  296. * @param string $id The unique name/identity of the block to get
  297. */
  298. function get($id="") {
  299. global $RESPONSE;
  300. debug_trace($this);
  301. $this->exists = false;
  302.  
  303. // Assign the ID if given..
  304. if ($id != "") $this->blockid = $id;
  305.  
  306. // Try and find it..
  307. if ($RESPONSE->multilang) {
  308. $q = "SELECT * FROM ax_block, ax_language";
  309. $q .= " WHERE ax_block.block_id='" . addslashes($this->blockid) . "'";
  310. $q .= " AND ax_language.lang_id=ax_block.lang_id";
  311. }
  312. else {
  313. $q = "SELECT * FROM ax_block";
  314. $q .= " WHERE ax_block.block_id='" . addslashes($this->blockid) . "'";
  315. }
  316. $frq = dbrecordset($q);
  317. if ($frq->hasdata) {
  318. $this->layoutid = $frq->field("layout_id");
  319. $this->block_desc = $frq->field("block_desc");
  320. $this->cols = $frq->field("cols");
  321. if ($this->cols == "" || $this->cols <= 0) {
  322. $this->cols = 1;
  323. }
  324. if ($RESPONSE->multilang) {
  325. $this->language = $frq->field("lang_id");
  326. $this->lang_encoding = $frq->field("char_encoding");
  327. $this->lang_direction = $frq->field("direction");
  328. }
  329. $this->gutter_width = $frq->field("gutter_width");
  330. $this->gutter_colour = $frq->field("gutter_colour");
  331. $this->blocklet_sep = $frq->field("blocklet_sep");
  332. $this->background_colour = $frq->field("background_colour");
  333. $this->background_img = $frq->field("background_img");
  334. if ($this->background_img == "") {
  335. $this->background_img = NULLVALUE;
  336. }
  337. $this->justify = $frq->field("justify");
  338. $this->valign = $frq->field("valign");
  339. $this->border_width = $frq->field("border_width");
  340. $this->border_colour = $frq->field("border_colour");
  341. $this->block_style = $frq->field("block_style");
  342. $this->block_type = $frq->field("block_type");
  343. $this->exportable = $frq->istrue("exportable");
  344. $this->wysiwyg = $frq->istrue("wysiwyg");
  345. $this->exists = true;
  346.  
  347. // Get any defined blocklets. We do this here in one query
  348. // rather than using the blocklet class get() method, which
  349. // would be very inefficient..
  350. $q = "SELECT *";
  351. $q .= " FROM ax_block_blocklet bb, ax_blocklet b";
  352. $q .= " WHERE bb.block_id='" . addslashes($this->blockid) . "'";
  353. $q .= " AND b.blocklet_id=bb.blocklet_id";
  354. $q .= " ORDER BY bb.display_order";
  355. $frq = dbrecordset($q);
  356. if ($frq->hasdata) {
  357. do {
  358. $blockletid = $frq->field("blocklet_id");
  359. $blocklet = new blocklet();
  360. $blocklet->blockletid = $blockletid;
  361. $blocklet->visible = $frq->istrue("visible");
  362. $blocklet->display_order = $frq->field("display_order");
  363. $blocklet->blocklet_desc = $frq->field("blocklet_desc");
  364. $blocklet->type = $frq->field("blocklet_type");
  365. $blocklet->width = $frq->field("blocklet_width");
  366. $blocklet->justify = $frq->field("justify");
  367. $blocklet->heading = $frq->field("heading");
  368. $blocklet->heading_level = $frq->field("heading_level");
  369. $blocklet->heading_colour = $frq->field("heading_colour");
  370. $blocklet->ruler = $frq->field("ruler");
  371. $blocklet->ruler_width = $frq->field("ruler_width");
  372. $blocklet->ruler_size = $frq->field("ruler_size");
  373. $blocklet->ruler_colour = $frq->field("ruler_colour");
  374. $blocklet->content = $frq->field("content");
  375. $blocklet->content_size = $frq->field("content_size");
  376. $blocklet->content_colour = $frq->field("content_colour");
  377. $blocklet->blocklet_style = $frq->field("blocklet_style");
  378. $blocklet->table_style = $frq->field("table_style");
  379. $blocklet->table_autojustify = $frq->istrue("table_autojustify");
  380. $blocklet->table_rowstripes = $frq->istrue("table_rowstripes");
  381. // Stash blocklet..
  382. $this->blocklets[$blockletid] = $blocklet;
  383. } while ($frq->get_next());
  384. }
  385. }
  386. debug_trace();
  387. // Return true if at least the block exists..
  388. return $this->exists;
  389. } // get
  390. // ....................................................................
  391. /**
  392. * Save the block.
  393. * Save this block to the database. Create a new one if it
  394. * doesn't already exist.
  395. */
  396. function put() {
  397. debug_trace($this);
  398. // Deal with brand new block..
  399. start_transaction();
  400. if ($this->exists) {
  401. $frq = new dbupdate("ax_block");
  402. $frq->where("block_id=$this->blockid");
  403. }
  404. else {
  405. $frq = new dbinsert("ax_block");
  406. $frq->set("block_id", $this->blockid);
  407. }
  408. $frq->set("layout_id", $this->layoutid);
  409. $frq->set("block_desc", $this->block_desc);
  410. $frq->set("lang_id", $this->language);
  411. $frq->set("cols", $this->cols);
  412. $frq->set("gutter_width", $this->gutter_width);
  413. $frq->set("gutter_colour", $this->gutter_colour);
  414. $frq->set("background_colour", $this->background_colour);
  415. $frq->set("background_img", $this->background_img);
  416. $frq->set("justify", $this->justify);
  417. $frq->set("valign", $this->valign);
  418. $frq->set("border_width", $this->border_width);
  419. $frq->set("border_colour", $this->border_colour);
  420. $frq->set("blocklet_sep", $this->blocklet_sep);
  421. $frq->set("block_style", $this->block_style);
  422. $frq->set("block_type", $this->block_type);
  423. $frq->set("exportable", $this->exportable);
  424. $frq->set("last_modified", 'now()');
  425. $this->exists = $frq->execute();
  426.  
  427. // Save any blocklets..
  428. if (isset($this->blocklets)) {
  429. foreach ($this->blocklets as $blocklet) {
  430. $blockletexists = $blocklet->exists;
  431. $blocklet->put();
  432. if ($blockletexists) {
  433. $frq = new dbupdate("ax_block_blocklet");
  434. $frq->where("block_id=$this->blockid");
  435. $frq->where("AND blocklet_id=$blocklet->blockletid");
  436. }
  437. else {
  438. $frq = new dbinsert("ax_block_blocklet");
  439. $frq->set("block_id", $this->blockid);
  440. $frq->set("blocklet_id", $blocklet->blockletid);
  441. }
  442. $frq->set("visible", $blocklet->visible);
  443. $frq->set("display_order", $blocklet->display_order);
  444. $frq->execute();
  445. } // foreach
  446. }
  447. commit();
  448. debug_trace();
  449. } // put
  450. // ....................................................................
  451. /**
  452. * Replicate this block into a new block with a new set of blocklets
  453. * as a complete content copy of this original block.
  454. * NOTE: We end up with this current block as the replicated one.
  455. */
  456. function replicate($layoutname="") {
  457. $this->activate_editing();
  458. $this->blockeditor->replicate($layoutname);
  459. } // replicate
  460. // ....................................................................
  461. /**
  462. * Add a new blocklet to the block.
  463. * This adds a new blocklet to the list, but does not add any records
  464. * to the database.
  465. */
  466. function add_blocklet() {
  467. debug_trace($this);
  468. $blocklet = new blocklet();
  469. $blocklet->blockletid = get_next_sequencevalue("seq_blocklet_id", "ax_blocklet", "blocklet_id");
  470. $blocklet->display_order = 999;
  471. $this->blocklets[$blocklet->blockletid] = $blocklet;
  472. debug_trace();
  473. } // add_blocklet
  474. // ....................................................................
  475. /**
  476. * Remove blocklet from the block.
  477. * We remove the entry from the block_blocklet link table, and, if it
  478. * is the last link involving the blocklet we delete the blocklet record.
  479. */
  480. function remove_blocklet($id) {
  481. debug_trace($this);
  482. if (isset($this->blocklets[$id])) {
  483. $q = "DELETE FROM ax_block_blocklet";
  484. $q .= " WHERE block_id=$this->blockid";
  485. $q .= " AND blocklet_id=$id";
  486. dbcommand($q);
  487. $chkq = "SELECT * FROM ax_block_blocklet WHERE blocklet_id=$id";
  488. if (!$chkq->hasdata) {
  489. $blocklet = $this->blocklets[$id];
  490. $blocklet->delete();
  491. }
  492. // Remove it from our list..
  493. unset($this->blocklets[$id]);
  494. }
  495. debug_trace();
  496.  
  497. } // remove_blocklet
  498. // ....................................................................
  499. /**
  500. * Delete this block from the database. NB: we do not rely on RI to do
  501. * this since various versions of Postgres don't support this nicely.
  502. * All related entities are explicitly deleted in a transaction.
  503. */
  504. function delete() {
  505. $this->activate_editing();
  506. $this->blockeditor->delete();
  507. } // delete
  508. // ....................................................................
  509. /**
  510. * Index the block.
  511. * Index all blocklets of this block using Lucene, if Lucene indexing is
  512. * enabled (via the configvalue 'Lucene Site Indexing'). This has no effect
  513. * unless you are using the Axyl framework.
  514. * Notes: This method indexes the blocklets in this block which are at
  515. * the present time in the database, ie. not the blocklets as defined in
  516. * this block object. This method is usually called from the POSTprocess()
  517. * method, just after saving any changes to the database.
  518. * @param string $path The relative path to the webpage this block is in
  519. * @param string $title The title of the webpage this block is in
  520. * @param string $category The category string to index content with
  521. * @param string $metadata Metadata object containing metadata to index
  522. */
  523. function index($path, $title, $category="", $metadata=false) {
  524. global $RESPONSE, $CONTEXT;
  525. debug_trace($this);
  526. if ( isset($CONTEXT) && $CONTEXT->configvalue("Lucene Site Indexing") ) {
  527. include_once("lucene-defs.php");
  528. // Read content from DB since it may have just been saved..
  529. $q = "SELECT b.heading, b.content, b.blocklet_desc";
  530. $q .= " FROM ax_block_blocklet bb, ax_blocklet b";
  531. $q .= " WHERE bb.block_id=$this->blockid";
  532. $q .= " AND b.blocklet_id=bb.blocklet_id";
  533. $bQ = dbrecordset($q);
  534. $allcontent = array();
  535. $allcontent[] = $RESPONSE->head->title;
  536. $allcontent[] = $this->block_desc;
  537. if ($bQ->hasdata) {
  538. do {
  539. $allcontent[] = $bQ->field("heading");
  540. $allcontent[] = $bQ->field("content");
  541. $bkt_desc = $bQ->field("blocklet_desc");
  542. if ($bkt_desc != "(enter a blocklet description)") {
  543. $allcontent[] = $bkt_desc;
  544. }
  545. } while ($bQ->get_next());
  546. }
  547. $I = new lucene_indexmsg();
  548. $I->index_field("category:Text", ($category == "" ? "sitecontent" : $category));
  549. $I->index_field("path:Text", $path);
  550. $I->index_field("title:Text", $title);
  551. $I->index_field("lastmodified:Date", time());
  552. if ($RESPONSE->multilang && $this->language > 0) {
  553. $I->index_field("language:Text", $this->language);
  554. }
  555. // Add in any metadata fields being supplied..
  556. if ($metadata !== false && count($metadata->metadata_elements) > 0) {
  557. foreach ($metadata->metadata_elements as $element_id => $element) {
  558. if ($element->tag_name != "" && $element->tag_value != "") {
  559. $I->index_field($element->tag_name . ":Text", $element->tag_value);
  560. }
  561. }
  562. }
  563. $I->index_content("AXYLBLOCKID_$this->blockid", implode(" ", $allcontent));
  564. $I->send();
  565. }
  566. debug_trace();
  567. } // index
  568. // ....................................................................
  569. /**
  570. * Un-index the block.
  571. * Un-index this block from Lucene, if Lucene indexing is enabled (via
  572. * the configvalue 'Lucene Site Indexing'). This has no effect if you are
  573. * not using the Axyl framework.
  574. */
  575. function unindex() {
  576. global $CONTEXT;
  577. debug_trace($this);
  578. // Deal with Lucene indexing if enabled. In this case we then
  579. // use the unique block_id as the index ID, and unindex from
  580. // Lucene so that references to this block are removed..
  581. if ( isset($CONTEXT) && $CONTEXT->configvalue("Lucene Site Indexing") ) {
  582. include_once("lucene-defs.php");
  583. $UI = new lucene_unindexmsg();
  584. $UI->unindex("AXYLBLOCKID_$this->blockid");
  585. $UI->send();
  586. }
  587. debug_trace();
  588. } // unindex
  589. // ....................................................................
  590. /**
  591. * Render the Wysiwyg editing suite.
  592. * @return string The HTML for the editing suite form etc.
  593. * @access private
  594. */
  595. function wysiwyg_editform($lang_encoding, $lang_direction) {
  596. $this->activate_editing();
  597. return $this->blockeditor->wysiwyg_editform($lang_encoding, $lang_direction);
  598. } // wysiwyg_editform
  599. // ....................................................................
  600. /**
  601. * Render the block editing suite.
  602. * @return string The HTML for the editing suite form etc.
  603. * @access private
  604. */
  605. function block_editform($lang_encoding, $lang_direction) {
  606. $this->activate_editing();
  607. return $this->blockeditor->block_editform($lang_encoding, $lang_direction);
  608. } // block_editform
  609. // ....................................................................
  610. /**
  611. * Render the block content.
  612. * @return string The HTML
  613. * @access private
  614. */
  615. function blockcontent($lang_encoding, $lang_direction) {
  616. debug_trace($this);
  617. global $LIBDIR;
  618. global $RESPONSE;
  619. $editing = false;
  620.  
  621. $s = "";
  622.  
  623. // Render the blocklets in a table..
  624. $Tvw = new table($this->blockid);
  625.  
  626. // Apply supplemental style, if given..
  627. if ($this->block_style != "") {
  628. $Tvw->setstyle($this->block_style);
  629. }
  630.  
  631. // Apply background image if there is one..
  632. if ($this->background_img != NULLVALUE) {
  633. $qQ = dbrecordset("SELECT * FROM ax_catalog WHERE cat_id=$this->background_img");
  634. if ($qQ->hasdata) {
  635. $src = $qQ->field("filepath");
  636. $Tvw->setbackground($src);
  637. }
  638. }
  639.  
  640. // Apply border styles, if we have a border..
  641. $bdrstyle = "";
  642. if ($this->border_width > 0) {
  643. $bdrstyle = "border-width:" . $this->border_width . "px;";
  644. $bdrstyle .= "border-color:" . $this->border_colour . ";";
  645. $bdrstyle .= "border-style:solid;";
  646. $Tvw->setstyle($bdrstyle);
  647. }
  648.  
  649. if ($this->mode != "previewing" && $RESPONSE->ismemberof_group_in( array_merge($this->editor_groups, $this->author_groups) )) {
  650. $editor = true;
  651. if ($bdrstyle == "") {
  652. $Tvw->setstyle("border-width:1px;border-style:dotted;border-color:#ff0000;");
  653. }
  654. // Tools for the toolbar
  655. $toolbar = array();
  656. if ($this->user_can_edit()) {
  657. $toolbar[] = new form_imagebutton("_edit", "", "", "$LIBDIR/img/_edit.gif", "Edit block", 42, 15);
  658. }
  659.  
  660. // Toolbar table
  661. $Tbar = new table("toolbar");
  662. $Tbar->tr("axtitle");
  663. $Tbar->th("[Block]", "axtitle");
  664. $Tbar->th_alignment("", "top");
  665. $tools = "";
  666. foreach ($toolbar as $tool) {
  667. $tools .= $tool->render();
  668. }
  669. $Tbar->th($tools, "axtitle");
  670. $Tbar->th_css("text-align:right");
  671.  
  672. // Put toolbar into table..
  673. $Tvw->tr("axtitle");
  674. $Tvw->td( $Tbar->render(), "axtitle" );
  675. }
  676.  
  677. // Generate an ordered array of our visible blocklets..
  678. if (isset($this->blocklets)) {
  679. $ordblocklets = array();
  680. foreach ($this->blocklets as $blocklet) {
  681. if ($blocklet->visible) {
  682. $ordblocklets[$blocklet->blockletid] = $blocklet->display_order;
  683. }
  684. }
  685. asort($ordblocklets, SORT_NUMERIC);
  686. $visible_blocklets = array();
  687. foreach($ordblocklets as $blockletid => $order) {
  688. $visible_blocklets[] = $blockletid;
  689. }
  690.  
  691. // Ascertain blocklet display metrics..
  692. $tot_blocklets = count($visible_blocklets);
  693. $tot_rows = ceil($tot_blocklets / $this->cols);
  694.  
  695. // Render the blocklets..
  696. $Tvw->tr();
  697. $Tvw->td();
  698. $Tvw->td_alignment("", "top");
  699.  
  700. $Tbl = new table("B" . $this->blockid);
  701. if ($this->background_colour != "") {
  702. $Tbl->setbgcolor($this->background_colour);
  703. }
  704. $Tbl->tr();
  705. $bc = 0;
  706. $col = 1;
  707. $widthpct = floor(100 / $this->cols);
  708. foreach ($visible_blocklets as $blockletid) {
  709. $blocklet = $this->blocklets[$blockletid];
  710. if ($bc++ % $tot_rows == 0) {
  711. if (isset($Tcol)) {
  712. // Put the last blocklets column in..
  713. $Tbl->td_content($Tcol->render());
  714. unset($Tcol);
  715.  
  716. // If multi-column and guttering enabled, make a
  717. // gutter column here..
  718. if ($this->cols > 1 && $this->gutter_width > 0) {
  719. $gutc = (($this->gutter_colour != "") ? $this->gutter_colour : "black");
  720. $Tbl->td();
  721. //$Tbl->td_metrics($this->gutter_width);
  722. $guts .= "border-right:" . $this->gutter_width . "px ";
  723. $guts .= " solid";
  724. $guts .= " $this->gutter_colour;";
  725. $Tbl->td_css($guts);
  726. }
  727. }
  728. // Make new cell for next column..
  729. $Tbl->td();
  730. $Tbl->td_alignment("", "top");
  731. if ($bc == $tot_blocklets) $widthpct += 1;
  732. $Tbl->td_metrics("$widthpct%");
  733. $Tcol = new table("B" . $this->blockid . "_" . $col++);
  734. }
  735. $Tcol->tr();
  736. $Tcol->td($blocklet->html());
  737. if ($this->blocklet_sep > 0 && $tot_blocklets > 1 && $bc < $tot_blocklets) {
  738. $Tcol->tr();
  739. $Tcol->td();
  740. $Tcol->td_height($this->blocklet_sep);
  741. }
  742. }
  743. if (isset($Tcol)) {
  744. $Tbl->td_content($Tcol->render());
  745. }
  746. $Tvw->td_content( $Tbl->render() );
  747. }
  748.  
  749. // Render the content table..
  750. $s .= $Tvw->render();
  751.  
  752. debug_trace();
  753. // Return the html..
  754. return $s;
  755. } // blockcontent
  756.  
  757. // ....................................................................
  758. /**
  759. * Render the block content as a CSV formatted stream. This is designed
  760. * to facilitate the exporting of complex tables of data as CSV format
  761. * for importing into spreadsheets, or databases etc.
  762. * @return string The content in CSV format.
  763. */
  764. function csv() {
  765. debug_trace($this);
  766. $s = "";
  767. // Generate an ordered array of our visible blocklets..
  768. if (isset($this->blocklets)) {
  769. $ordblocklets = array();
  770. foreach ($this->blocklets as $blocklet) {
  771. if ($blocklet->visible) {
  772. $ordblocklets[$blocklet->blockletid] = $blocklet->display_order;
  773. }
  774. }
  775. asort($ordblocklets, SORT_NUMERIC);
  776. $visible_blocklets = array();
  777. while (list($blockletid, $order) = each($ordblocklets)) {
  778. $visible_blocklets[] = $blockletid;
  779. }
  780. foreach ($visible_blocklets as $blockletid) {
  781. $blocklet = $this->blocklets[$blockletid];
  782. $s .= $blocklet->csv() . "\n";
  783. }
  784. }
  785. debug_trace();
  786. // Return the csv stream..
  787. return $s;
  788. } // csv
  789.  
  790. // ....................................................................
  791. /**
  792. * Render the block content according to the mode of operation
  793. * we are in. Possible modes: 'viewing', 'editing', 'saving'.
  794. * @return string The HTML
  795. */
  796. function html() {
  797. debug_trace($this);
  798. global $LIBDIR;
  799. global $RESPONSE;
  800. global $edit_blockid;
  801.  
  802. // Language details..
  803. $lang_encoding = "";
  804. $lang_direction = "";
  805. $language = $this->language;
  806. if ($RESPONSE->multilang) {
  807. if ($this->language != 0) {
  808. $lang_encoding = $this->lang_encoding;
  809. $lang_direction = $this->lang_direction;
  810. }
  811. else {
  812. if ($this->layout_language != 0) {
  813. $language = $this->layout_language;
  814. $lang_encoding = $this->layout_lang_encoding;
  815. $lang_direction = $this->layout_lang_direction;
  816. }
  817. }
  818. // Make sure RESPONSE takes note of language setting. If this
  819. // language was already added, it doesn't matter..
  820. if ($language != 0) {
  821. $RESPONSE->add_language($language);
  822. }
  823. }
  824.  
  825. $s = "";
  826. // Start form for editing..
  827. if ($this->exportable || $RESPONSE->ismemberof_group_in( array_merge($this->editor_groups, $this->author_groups) )) {
  828. $s .= "<form name=\"$this->blockfm\" method=\"post\" enctype=\"multipart/form-data\">";
  829. }
  830.  
  831. switch($this->mode) {
  832. case "editing":
  833. // Make sure edit request is meant for us..
  834. if (!isset($edit_blockid) || $edit_blockid != $this->blockid) {
  835. return "";
  836. }
  837. // Deal with first block edit. In this case it won't yet
  838. // exist in the database, so we create it here..
  839. if (!$this->exists) {
  840. $this->put();
  841. }
  842. $this->mode = "saving";
  843. // Show the appropriate editing form..
  844. switch ($this->block_type) {
  845. case WYSIWYG_EDITOR:
  846. $s .= $this->wysiwyg_editform($lang_encoding, $lang_direction);
  847. break;
  848. default:
  849. $s .= $this->block_editform($lang_encoding, $lang_direction);
  850. } // switch
  851. break;
  852.  
  853. default:
  854. if ($this->mode != "viewing" && $this->mode != "previewing") {
  855. $this->mode = "viewing";
  856. }
  857. $s .= $this->blockcontent($lang_encoding, $lang_direction);
  858. if ($this->exportable) {
  859. $expbtn = new form_imagebutton("_exportblock");
  860. $expbtn->setimage("$LIBDIR/img/_export.gif", "Export this information in CSV format");
  861. $s .= "<p>" . $expbtn->render() . "</p>";
  862. }
  863. } // switch
  864.  
  865. // Finish the form..
  866. if ($this->exportable || $RESPONSE->ismemberof_group_in( array_merge($this->editor_groups, $this->author_groups) )) {
  867. // Include action hidden field, and block ID
  868. $mode = new form_hiddenfield("blockmode", $this->mode);
  869. $blid = new form_hiddenfield("edit_blockid", $this->blockid);
  870. $s .= $mode->render() . $blid->render();
  871. // Layout version hidden field
  872. if ($this->layout_version != VERSION_UNDEFINED) {
  873. $lvers = new form_hiddenfield("layout_version", $this->layout_version);
  874. $lvcnt = new form_hiddenfield("layout_version_count", $this->layout_version_count);
  875. $s .= $lvers->render() . $lvcnt->render();
  876. }
  877. $s .= "</form>\n";
  878. }
  879.  
  880. return $s;
  881. } // html
  882. // ....................................................................
  883. /**
  884. * Process a block edit form POST.
  885. * Assume that the fields have been submitted in a form as named
  886. * in the config, and grab the POSTed values. This method is executed
  887. * from the constructor usually, before anything is read in from
  888. * the database. We get first shot to change data here.
  889. * @param text $id The identity of the set to update from POST
  890. * @access private
  891. */
  892. function POSTprocess() {
  893. debug_trace($this);
  894. global $CONTEXT, $RESPONSE, $LIBDIR;
  895. global $edit_blockid;
  896.  
  897. if (isset($edit_blockid) && $edit_blockid == $this->blockid) {
  898. global $_done_x, $_edit_x, $_exportblock_x, $blockmode;
  899. $this->mode = $blockmode;
  900. switch ($this->mode) {
  901. case "viewing":
  902. // Check for editing mode..
  903. if (isset($_edit_x)) {
  904. $this->mode = "editing";
  905. }
  906. // Check for user export button-press. In this
  907. // case we deliver CSV content, and exit..
  908. elseif (isset($_exportblock_x)) {
  909. $exptitle = $RESPONSE->body->title;
  910. if ($exptitle == "") {
  911. $exptitle = $this->blockid;
  912. }
  913. $this->get();
  914. $csv = $this->csv();
  915. $RESPONSE->discard();
  916. $RESPONSE->set_encoding("", "text/csv");
  917. header("Content-Disposition: attachment; filename=$exptitle.csv");
  918. echo $csv;
  919. exit;
  920. }
  921. break;
  922.  
  923. case "saving":
  924. if ($edit_blockid == $this->blockid) {
  925. global $_csvimport_x, $blocklet_id;
  926. global $_save_x, $_cancel_x, $_done_x;
  927. global $_wysiwygpost_form;
  928. global $_recmaintpost_form;
  929. global $_recmaintpost_data;
  930. global $_recmaintpost_flds;
  931. global $_recmaintpost_dels;
  932. global $_recmaintpost_order;
  933.  
  934. // Let me out of here..
  935. if (isset($_done_x) || isset($_cancel_x)) {
  936. // Drop through to viewing..
  937. $this->mode = "viewing";
  938. }
  939. // Posted record maintenance data..
  940. elseif ( isset($_recmaintpost_form)
  941. && $_recmaintpost_form == $this->blockfm) {
  942. // Posted CSV table data. This data is to be appended to
  943. // the blocklet content as a table..
  944. if (isset($_csvimport_x) && isset($blocklet_id)) {
  945. $up = new fileupload();
  946. if ($up->uploaded_count >= 1) {
  947. // Process a uploaded file(s)..
  948. $file_mime = $up->mimetype;
  949. if ($file_mime != CONTENT_CSV) {
  950. $file_mime = mimetype_from_filename($up->filename);
  951. }
  952. if ($file_mime == CONTENT_CSV) {
  953. // Process the file..
  954. $fup = new csv_inputfile($up->filepath);
  955. $tablerow = false;
  956. $newtable = "";
  957. if ($fup->opened) {
  958. do {
  959. $tablerow = $fup->readln();
  960. if ($tablerow) {
  961. $newtable .= implode("|", $tablerow) . "\n";
  962. }
  963. } while ($tablerow);
  964. $fup->closefile();
  965. if ($newtable != "") {
  966. $ob = dbrecordset("SELECT content FROM ax_blocklet WHERE blocklet_id=$blocklet_id");
  967. if ($ob->hasdata) {
  968. $orig_content = $ob->field("content");
  969. if ($orig_content != "") $orig_content .= "\n";
  970. $ub = new dbupdate("ax_blocklet");
  971. $ub->set("content", $orig_content . $newtable);
  972. $ub->set("blocklet_type", "table");
  973. $ub->where("blocklet_id=$blocklet_id");
  974. $ub->execute();
  975. }
  976. }
  977. }
  978. else {
  979. $emsg = "failed to open uploaded file: '$up->filename'";
  980. $errmsgs[] = $emsg;
  981. debugbr($emsg, DBG_DEBUG);
  982. }
  983. }
  984. else {
  985. $emsg = "Not a comma-separated variable (CSV) file: '$up->filename'";
  986. $errmsgs[] = $emsg;
  987. debugbr($emsg, DBG_DEBUG);
  988. }
  989. }
  990. else {
  991. $emsg = "Nothing was uploaded.";
  992. $errmsgs[] = $emsg;
  993. debugbr($emsg, DBG_DEBUG);
  994. }
  995. // Drop through to viewing..
  996. $this->mode = "editing";
  997.  
  998. } // if CSV import
  999.  
  1000. else {
  1001. // Deal with Save, Delete, Re-ordering etc..
  1002. if (isset($_recmaintpost_dels) && $_recmaintpost_dels != "") {
  1003. $blocklet_delids = explode(FIELD_DELIM, $_recmaintpost_dels);
  1004. foreach ($blocklet_delids as $delblockletid) {
  1005. dbcommand("DELETE FROM ax_blocklet WHERE blocklet_id=$delblockletid");
  1006. }
  1007. }
  1008. // Blocklet adds and saves..
  1009. if (isset($_recmaintpost_data) && $_recmaintpost_data != "") {
  1010. $blockletrecs = explode(RECORD_DELIM, $_recmaintpost_data);
  1011. $blocklet_fields = explode(",", $_recmaintpost_flds);
  1012. foreach ($blockletrecs as $blockletrec) {
  1013. $blocklet_values = explode(FIELD_DELIM, $blockletrec);
  1014. $blockletid = array_shift($blocklet_values);
  1015. // Cater for new creations..
  1016. if (strstr($blockletid, "NEW_")) {
  1017. $savedid = $blockletid;
  1018. $blockletid = get_next_sequencevalue("seq_blocklet_id", "ax_blocklet", "blocklet_id");
  1019. $ib = new dbinsert("ax_blocklet");
  1020. $ib->set("blocklet_id", $blockletid);
  1021. $ib->execute();
  1022. $ibb = new dbinsert("ax_block_blocklet");
  1023. $ibb->set("block_id", $this->blockid);
  1024. $ibb->set("blocklet_id", $blockletid);
  1025. $ibb->set("display_order", 99);
  1026. $ibb->execute();
  1027. // Fix up potential re-ordering id..
  1028. if (isset($_recmaintpost_order)) {
  1029. $_recmaintpost_order = str_replace("$savedid", "$blockletid", $_recmaintpost_order);
  1030. }
  1031. }
  1032. // Update the blocklet data..
  1033. $bu = new dbupdate("ax_blocklet");
  1034. $bu->where("blocklet_id=$blockletid");
  1035. $pos = 0;
  1036. foreach ($blocklet_fields as $blocklet_field) {
  1037. if ($blocklet_field == "visible") {
  1038. $visible_value = $blocklet_values[$pos++];
  1039. }
  1040. else {
  1041. $bu->set($blocklet_field, $blocklet_values[$pos++]);
  1042. }
  1043. }
  1044. $bu->execute();
  1045. // Now save the visibility flag..
  1046. if (isset($visible_value)) {
  1047. $bu = new dbupdate("ax_block_blocklet");
  1048. $bu->where("block_id=$this->blockid AND blocklet_id=$blockletid");
  1049. $bu->set("visible", ($visible_value == "t"));
  1050. $bu->execute();
  1051. }
  1052. } // foreach blockletrecs
  1053. }
  1054.  
  1055. // Save block properties..
  1056. global $block_desc, $language, $block_style;
  1057. global $cols, $gutter_width, $gutter_colour;
  1058. global $background_colour, $background_img;
  1059. global $block_justify, $block_valign;
  1060. global $block_border_width, $block_border_colour;
  1061. global $blocklet_sep, $block_exportable;
  1062. if (isset($cols) && $cols > 0) {
  1063. $bu = new dbupdate("ax_block");
  1064. $bu->where("block_id=$this->blockid");
  1065. $bu->set("block_desc", $block_desc);
  1066. $bu->set("lang_id", $language);
  1067. $bu->set("cols", $cols);
  1068. $bu->set("gutter_width", $gutter_width);
  1069. $bu->set("gutter_colour", $gutter_colour);
  1070. $bu->set("blocklet_sep", $blocklet_sep);
  1071. $bu->set("background_colour", $background_colour);
  1072. $bu->set("background_img", $background_img);
  1073. $bu->set("justify", $block_justify);
  1074. $bu->set("valign", $block_valign);
  1075. $bu->set("border_width", $block_border_width);
  1076. $bu->set("border_colour", $block_border_colour);
  1077. $bu->set("block_style", $block_style);
  1078. $bu->set("exportable", isset($block_exportable));
  1079. $bu->execute();
  1080. }
  1081.  
  1082. // Check/save blocklet ordering..
  1083. if (isset($_recmaintpost_order) && $_recmaintpost_order != "") {
  1084. $ord = 1;
  1085. $idlist = explode(FIELD_DELIM, $_recmaintpost_order);
  1086. foreach ($idlist as $blockletid) {
  1087. $upd = new dbupdate("ax_block_blocklet");
  1088. $upd->where("block_id=$this->blockid AND blocklet_id=$blockletid");
  1089. $upd->set("display_order", $ord);
  1090. $upd->execute();
  1091. $ord += 1;
  1092. }
  1093. }
  1094.  
  1095. // Index the block with current webpage path and title..
  1096. global $layout_version, $layout_version_count;
  1097. if (!isset($layout_version) ||
  1098. $layout_version == VERSION_LIVE ||
  1099. $layout_version_count == 1) {
  1100. debugbr("indexing saved block. Layout ver=$layout_version", DBG_DEBUG);
  1101. $this->get();
  1102. $this->index($RESPONSE->requested, $RESPONSE->head->title);
  1103. }
  1104.  
  1105. // Drop through to viewing..
  1106. $this->mode = "viewing";
  1107. }
  1108. }
  1109. // Is it a wysiwyg post..
  1110. elseif ( isset($_wysiwygpost_form)
  1111. && $_wysiwygpost_form == $this->blockfm) {
  1112. global $wysiwyg_content;
  1113. $this->get();
  1114. $bb = current($this->blocklets);
  1115. if (isset($bb) && isset($bb->blockletid)) {
  1116. $bbup = new dbupdate("ax_blocklet");
  1117. $bbup->set("content", $wysiwyg_content);
  1118. $bbup->where("blocklet_id=$bb->blockletid");
  1119. $bbup->execute();
  1120. $this->blocklets[$bb->blockletid] = $bb;
  1121. }
  1122. // Also save some of the block properties..
  1123. global $block_desc, $block_style;
  1124. global $background_colour, $background_img;
  1125. global $block_justify, $block_valign;
  1126. global $block_border_width, $block_border_colour;
  1127. $bu = new dbupdate("ax_block");
  1128. $bu->where("block_id=$this->blockid");
  1129. $bu->set("block_desc", $block_desc);
  1130. $bu->set("background_colour", $background_colour);
  1131. $bu->set("background_img", $background_img);
  1132. $bu->set("justify", $block_justify);
  1133. $bu->set("valign", $block_valign);
  1134. $bu->set("border_width", $block_border_width);
  1135. $bu->set("border_colour", $block_border_colour);
  1136. $bu->set("block_style", $block_style);
  1137. $bu->execute();
  1138.  
  1139. // Index the block with current webpage path and title..
  1140. global $layout_version, $layout_version_count;
  1141. if (!isset($layout_version) ||
  1142. $layout_version == VERSION_LIVE ||
  1143. $layout_version_count == 1) {
  1144. debugbr("indexing saved wysiwyg block. Layout ver=$layout_version", DBG_DEBUG);
  1145. $this->get();
  1146. $this->index($RESPONSE->requested, $RESPONSE->head->title);
  1147. }
  1148. }
  1149. }
  1150. break;
  1151. } // switch
  1152. }
  1153. // If the user preference says so, then set the mode to
  1154. // content preview mode..
  1155. $prefs = new configuration("preferences", $RESPONSE->userid);
  1156. if ($prefs->field_exists("Content Preview Mode")) {
  1157. if ($prefs->value("Content Preview Mode") === true) {
  1158. $this->mode = "previewing";
  1159. }
  1160. }
  1161. debug_trace();
  1162. } // POSTprocess
  1163.  
  1164.  
  1165.  
  1166. } // block class
  1167. // ----------------------------------------------------------------------
  1168.  
  1169. /**
  1170. * The blocklet is simply a part of a block. It is almost a 'paragraph' of
  1171. * content, excepting that a blocklet might have content of several text
  1172. * paragraphs, so it is something slightly different, hence the name. This
  1173. * class knows how to get, save and delete blocklets, and how to render
  1174. * them as html.
  1175. * @package cm
  1176. */
  1177. class blocklet extends RenderableObject {
  1178. /** blocklet ID */
  1179.  
  1180. var $blockletid;
  1181. /** Whether blocklet exists in database */
  1182.  
  1183. var $exists = false;
  1184. /** The description of the current blocklet */
  1185.  
  1186. var $desc = "";
  1187. /** The blocklet type: 'text', 'list', 'ordered', 'bullets', or 'table' */
  1188.  
  1189. var $type = "text";
  1190. /** The width % of the blocklet table */
  1191.  
  1192. var $width = 100;
  1193. /** Justification: 'left', 'right', 'centered' */
  1194.  
  1195. var $justify = "left";
  1196. /** blocklet heading */
  1197.  
  1198. var $heading;
  1199. /** blocklet heading level (1-6) */
  1200.  
  1201. var $heading_level = 3;
  1202. /** Heading colour */
  1203.  
  1204. var $heading_colour = "";
  1205. /** blocklet ruler: 'none', 'top', 'bottom' */
  1206.  
  1207. var $ruler = "none";
  1208. /** Ruler width percent: 0-100 */
  1209.  
  1210. var $ruler_width = 100;
  1211. /** Ruler pixel size */
  1212.  
  1213. var $ruler_size = 1;
  1214. /** Ruler colour */
  1215.  
  1216. var $ruler_colour = "";
  1217. /** Blocklet textual content */
  1218.  
  1219. var $content = "";
  1220. /** Content size adjustment -2 thru +2 */
  1221.  
  1222. var $content_size = 0;
  1223. /** Content colour */
  1224.  
  1225. var $content_colour = "";
  1226. /** Manual style to apply to content */
  1227.  
  1228. var $blocklet_style = "";
  1229. /** Table style to apply to content */
  1230.  
  1231. var $table_style = "";
  1232. /** True if we autojustify table */
  1233.  
  1234. var $table_autojustify = false;
  1235. /** True if we autojustify table */
  1236.  
  1237. var $table_rowstripes = false;
  1238. /** Whether blocklet is visible */
  1239.  
  1240. var $visible = true;
  1241. /** Display order of this blocklet */
  1242.  
  1243. var $display_order = 1;
  1244. // ....................................................................
  1245. /**
  1246. * Constructor
  1247. * Create a new blocklet object.
  1248. * @param string $id The unique identity of the blocklet.
  1249. */
  1250. function blocklet($id=NEW_BLOCKLET) {
  1251. $this->blockletid = $id;
  1252. $this->get($id);
  1253.  
  1254. } // blocklet
  1255. // ....................................................................
  1256. /**
  1257. * Get the blocklet.
  1258. * Retrieves the specified blocklet from database.
  1259. * @param string $id The unique integer identity of the blocklet to get.
  1260. */
  1261. function get($id) {
  1262. debug_trace($this);
  1263. $this->exists = false;
  1264. if ($id != NEW_BLOCKLET) {
  1265. // Try and read in existing blocklet info..
  1266. $q = "SELECT * FROM ax_blocklet";
  1267. $q .= " WHERE blocklet_id=$id";
  1268. $blq = dbrecordset($q);
  1269. if ($blq->hasdata) {
  1270. $this->blocklet_desc = $blq->field("blocklet_desc");
  1271. $this->type = $blq->field("blocklet_type");
  1272. $this->justify = $blq->field("justify");
  1273. $this->heading = $blq->field("heading");
  1274. $this->heading_level = $blq->field("heading_level");
  1275. $this->heading_colour = $blq->field("heading_colour");
  1276. $this->ruler = $blq->field("ruler");
  1277. $this->ruler_width = $blq->field("ruler_width");
  1278. $this->ruler_size = $blq->field("ruler_size");
  1279. $this->ruler_colour = $blq->field("ruler_colour");
  1280. $this->content = $blq->field("content");
  1281. $this->content_size = $blq->field("content_size");
  1282. $this->content_colour = $blq->field("content_colour");
  1283. $this->blocklet_style = $blq->field("blocklet_style");
  1284. $this->table_style = $blq->field("table_style");
  1285. $this->table_autojustify = $blq->istrue("table_autojustify");
  1286. $this->table_rowstripes = $blq->istrue("table_rowstripes");
  1287. $this->exists = true;
  1288. }
  1289. }
  1290. debug_trace();
  1291. // Return true if at least the blocklet exists..
  1292. return $this->exists;
  1293. } // get
  1294. // ....................................................................
  1295. /**
  1296. * Save the blocklet.
  1297. * Save this blocklet to the database. Create a new one if it
  1298. * doesn't already exist.
  1299. */
  1300. function put() {
  1301. debug_trace($this);
  1302. // Deal with brand new blocklet..
  1303. if (!$this->exists) {
  1304. // If we are in need of a new ID, then get one..
  1305. if ($this->blockletid == NEW_BLOCKLET) {
  1306. $this->blockletid = get_next_sequencevalue("seq_blocklet_id", "ax_blocklet", "blocklet_id");
  1307. }
  1308. $blq = new dbinsert("ax_blocklet");
  1309. $blq->set("blocklet_id", $this->blockletid);
  1310. }
  1311. else {
  1312. $blq = new dbupdate("ax_blocklet");
  1313. $blq->where("blocklet_id=$this->blockletid");
  1314. }
  1315. $blq->set("blocklet_desc", $this->blocklet_desc);
  1316. $blq->set("blocklet_type", $this->type);
  1317. $blq->set("justify", $this->justify);
  1318. $blq->set("heading", $this->heading);
  1319. $blq->set("heading_level", $this->heading_level);
  1320. $blq->set("heading_colour", $this->heading_colour);
  1321. $blq->set("ruler", $this->ruler);
  1322. $blq->set("ruler_width", $this->ruler_width);
  1323. $blq->set("ruler_size", $this->ruler_size);
  1324. $blq->set("ruler_colour", $this->ruler_colour);
  1325. $blq->set("content", $this->content);
  1326. $blq->set("content_size", $this->content_size);
  1327. $blq->set("content_colour", $this->content_colour);
  1328. $blq->set("blocklet_style", $this->blocklet_style);
  1329. $blq->set("table_style", $this->table_style);
  1330. $blq->set("table_autojustify", $this->table_autojustify);
  1331. $blq->set("table_rowstripes", $this->table_rowstripes);
  1332. $this->exists = $blq->execute();
  1333. debug_trace();
  1334. } // put
  1335. // ....................................................................
  1336. /**
  1337. * Delete the blocklet.
  1338. * Delete this blocklet from the database.
  1339. */
  1340. function delete() {
  1341. debug_trace($this);
  1342. // Don't assume RI wil delete the block_blocklets of this blocklet..
  1343. $del = new dbdelete("ax_block_blocklet");
  1344. $del->where("blocklet_id=$this->blockletid");
  1345. $del->execute();
  1346. $del = new dbdelete("ax_blocklet");
  1347. $del->where("blocklet_id=$this->blockletid");
  1348. $del->execute();
  1349. debug_trace();
  1350. } // delete
  1351. // ....................................................................
  1352. /**
  1353. * Content style.
  1354. * Returns an internal class style string based on the values of
  1355. * properties: content_colour and content_size. Returns the string
  1356. * as bare style specs 'font-size:0.8em;' etc.
  1357. * $access private
  1358. */
  1359. function content_css() {
  1360. $s = "";
  1361. if ($this->content_colour != "") {
  1362. $s .= "color:$this->content_colour;";
  1363. }
  1364. if ($this->content_size != 0) {
  1365. $em = number_format( (10 + $this->content_size)/10, 2);
  1366. $s .= "font-size:$em" . "em;";
  1367. }
  1368. if ($this->blocklet_style != "") {
  1369. $s .= $this->blocklet_style;
  1370. if (substr($this->blocklet_style, -1) != ";") {
  1371. $s .= ";";
  1372. }
  1373. }
  1374. return $s;
  1375. } // content_css
  1376. // ....................................................................
  1377. /**
  1378. * Content style.
  1379. * Returns an internal class style string based on the values of
  1380. * properties: content_colour and content_size. Returns the string
  1381. * as a full 'style="..." style, ready for a <span> tag etc..
  1382. * $access private
  1383. */
  1384. function content_style() {
  1385. $s = $this->content_css();
  1386. if ($s != "") $s = " style=\"$s\"";
  1387. return $s;
  1388. } // content_style
  1389. // ....................................................................
  1390. /**
  1391. * Format Content.
  1392. * Formats the given content according to the given content type.
  1393. * $access private
  1394. */
  1395. function format_content($content, $type="text", $css="") {
  1396. $s = "";
  1397. if (is_numeric($content)) $content = number_format($content);
  1398. switch ($type) {
  1399. // Vanilla list..
  1400. case "list":
  1401. $list = new vl($css);
  1402. $list->items = explode("\n", $content);
  1403. $s = $list->render();
  1404. break;
  1405. // Ordered list..
  1406. case "ordered":
  1407. $list = new ol($css);
  1408. $list->items = explode("\n", $content);
  1409. $s = $list->render();
  1410. break;
  1411. // Bullet points list..
  1412. case "bullets":
  1413. $list = new ul($css);
  1414. $list->items = explode("\n", $content);
  1415. $s = $list->render();
  1416. break;
  1417.  
  1418. case "table":
  1419. $t = new table("BKT_$this->blockletid");
  1420. if ($this->table_autojustify) {
  1421. $t->autojustify();
  1422. }
  1423. if ($this->table_rowstripes) {
  1424. $t->rowstripes("axyl_rowstripe_dark,axyl_rowstripe_lite");
  1425. }
  1426. $t->setpadding(2);
  1427. if ($this->table_style != "") {
  1428. $t->setcss($this->table_style);
  1429. }
  1430. // Assemble table..
  1431. $wprofile = "";
  1432. $rows = explode("\n", $content);
  1433. if (count($rows) > 0) {
  1434. foreach ($rows as $row) {
  1435. if (strstr($row, "~")) {
  1436. $wprofile = trim(str_replace("~", ",", $row));
  1437. }
  1438. else {
  1439. $t->tr();
  1440. // Heading rows use '^' separator..
  1441. if (strstr($row, "^")) {
  1442. $cells = explode("^", $row);
  1443. foreach ($cells as $cell) {
  1444. $t->th($cell);
  1445. $t->th_contentcss($css);
  1446. }
  1447. }
  1448. // Normal body rows use '|' separator..
  1449. else {
  1450. $cells = explode("|", $row);
  1451. foreach ($cells as $cell) {
  1452. $t->td($cell);
  1453. $t->td_alignment("", "top");
  1454. $t->td_contentcss($css);
  1455. }
  1456. }
  1457. }
  1458. } // foreach row
  1459. }
  1460. // Apply any width profile we got..
  1461. if ($wprofile != "") {
  1462. $t->set_width_profile($wprofile);
  1463. }
  1464. // Now put together the whole table..
  1465. $s .= $t->render();
  1466. break;
  1467.  
  1468. // Text content..
  1469. case "text":
  1470. // Paragraph content..
  1471. $style = $css;
  1472. if ($style != "") $style = " style=\"$style\"";
  1473. $para = "<p" . $style . ">";
  1474. $content = str_replace("\r\n\r\n", "$para", $content);
  1475. $s .= $sizetags . $para . $content . $sizeuntags;
  1476. break;
  1477.  
  1478. // Other content, raw content
  1479. default:
  1480. $s .= $sizetags . $content . $sizeuntags;
  1481. break;
  1482.  
  1483. } // switch
  1484.  
  1485. // Return content
  1486. return $s;
  1487. } // format_content
  1488.  
  1489. // ....................................................................
  1490. /**
  1491. * Render the blocklet as a CSV stream. We split the content types for
  1492. * this into 'table' and 'other'. For tables we use the "|" delimiter to
  1493. * determine where our commas go. For other content we basically just
  1494. * leave it as-is, only adding quotes.
  1495. * @return string The CSV formatted blocklet content.
  1496. */
  1497. function csv() {
  1498. debug_trace($this);
  1499. global $RESPONSE;
  1500.  
  1501. $content = strip_tags( $this->expanded_content() );
  1502. $content = str_replace("\r", "\n", $content);
  1503.  
  1504. // Format depending on type: 'text', 'list', 'ordered',
  1505. // 'bullets', or 'table'
  1506. switch ($this->type) {
  1507. case "table":
  1508. $rows = explode("\n", $content);
  1509. $content = "";
  1510. if (count($rows) > 0) {
  1511. foreach ($rows as $row) {
  1512. $csvrow = "";
  1513. if ($row != "" && $row != "\n" && !strstr($row, "~")) {
  1514. $row = str_replace("^", "|", $row);
  1515. $row = str_replace("\"", "\"\"", $row);
  1516. $bits = explode("|", $row);
  1517. $csvrow = "";
  1518. foreach ($bits as $bit) {
  1519. $csvrow .= "\"$bit\",";
  1520. }
  1521. $csvrow = substr($csvrow, 0, -1);
  1522. }
  1523. $content .= $csvrow;
  1524. if (substr($content, -1, 1) != "\n") {
  1525. $content .= "\n";
  1526. }
  1527. }
  1528. }
  1529. break;
  1530.  
  1531. default:
  1532. $content = str_replace("\"", "\"\"", $content);
  1533. $content = "\"$content\"";
  1534. break;
  1535. }
  1536. debug_trace();
  1537. // Return the CSV..
  1538. return $content;
  1539. } // csv
  1540. // ....................................................................
  1541. /**
  1542. * Process the current blocklet content for special tags. This effectively
  1543. * expands the special tags into 'real' content from database, or as image
  1544. * references etc. We return the expanded content as a string.
  1545. * @return string The new content, expanded as appropriate to the tags.
  1546. * $access private
  1547. */
  1548. function expanded_content() {
  1549. $content = $this->content;
  1550. $matches = array();
  1551. // NB: the original scheme for embedding Axyl content used object tags, however
  1552. // browsers didn't render these very well, so the current scheme uses img tags
  1553. // instead, whilst retaining a backward compatibility for existing websites.
  1554. $datapat = "/<object .*?axyl\/embedded-media.*?>|<img .*?axyl\/embedded-media.*?>/i";
  1555. while ( preg_match($datapat, $content, $matches) ) {
  1556. $datatag = $matches[0];
  1557. $attributes = extractAttributes($datatag);
  1558. if (!isset($attributes["name"])) {
  1559. $new_content = "";
  1560. $type = strtolower($attributes["type"]);
  1561. if (count($attributes) > 0 && $type == "axyl/embedded-media") {
  1562. $mediatype = strtolower($attributes["codetype"]);
  1563. switch ($mediatype) {
  1564. // DATA
  1565. case "data":
  1566. $quid = $attributes["id"];
  1567. $format = $attributes["format"];
  1568. $where = $attributes["where"];
  1569. $tableheadings = (isset($attributes["tableheadings"]));
  1570. if ($quid != "") {
  1571. $qQ = dbrecordset("SELECT * FROM ax_query_resource WHERE quid=$quid");
  1572. if ($qQ->hasdata) {
  1573. // Datasource content..
  1574. if ($qQ->field("q_query") != "") {
  1575. $datasrc = unserialize($qQ->field("q_query"));
  1576. // Apply any block-level where clause..
  1577. if ($where != "") {
  1578. if ($datasrc->where->total > 0) {
  1579. if (strtolower(substr($where, 0, 3)) != "and") {
  1580. $where = "and $where";
  1581. }
  1582. }
  1583. $datasrc->where($where);
  1584. }
  1585. $raw_content = "";
  1586. // Handle table headings if required..
  1587. if ($format == "table" && $tableheadings) {
  1588. $fieldnames = explode(",", $datasrc->fields->listed());
  1589. $headings = array();
  1590. foreach ($fieldnames as $fieldname) {
  1591. if (strstr($fieldname, ".")) {
  1592. $bits = explode(".", $fieldname);
  1593. $fieldname = $bits[1];
  1594. }
  1595. $headings[] = ucfirst(str_replace("_", " ", $fieldname));
  1596. }
  1597. $raw_content .= implode("^", $headings) . "\n";
  1598. }
  1599. // Get datasource data..
  1600. $datasrc->execute();
  1601. if ($datasrc->hasdata) {
  1602. do {
  1603. $data = array();
  1604. for ($i=0; $i < $datasrc->fields->total; $i++) {
  1605. $data[] = $datasrc->current_row[$i];
  1606. }
  1607. switch ($format) {
  1608. case "list":
  1609. case "ordered":
  1610. case "bullets":
  1611. $raw_content .= implode(" ", $data) . "\n";
  1612. break;
  1613. case "table":
  1614. $raw_content .= implode("|", $data) . "\n";
  1615. break;
  1616. default:
  1617. $raw_content .= implode(" ", $data);
  1618. } // switch
  1619. } while ($datasrc->get_next());
  1620. $new_content = $this->format_content(
  1621. $raw_content,
  1622. $format,
  1623. $this->content_css()
  1624. );
  1625. }
  1626. }
  1627. // Script-generated content..
  1628. elseif ($qQ->field("q_script") != "") {
  1629. debugbr("execute script here.", DBG_DEBUG);
  1630. }
  1631. }
  1632. }
  1633. // case data
  1634. break;
  1635. // IMAGE
  1636. case "image":
  1637. $catid = $attributes["id"];
  1638. $align = $attributes["align"];
  1639. $pad = $attributes["pad"];
  1640. $tooltip = $attributes["title"];
  1641. $width = $attributes["width"];
  1642. $height = $attributes["height"];
  1643. $border = $attributes["border"];
  1644. $bdcolor = $attributes["bordercolor"];
  1645. if ($catid != "") {
  1646. $qQ = dbrecordset("SELECT * FROM ax_catalog WHERE cat_id=$catid");
  1647. if ($qQ->hasdata) {
  1648. $src = $qQ->field("filepath");
  1649. if ($width == 0 || $width == "") $width = $qQ->field("width");
  1650. if ($width == 0 || $width == "") $width = false;
  1651. if ($height == 0 || $height == "") $height = $qQ->field("height");
  1652. if ($height == 0 || $height == "") $height = false;
  1653. $img=new img($src, $catid, $tooltip, $width, $height);
  1654. if ($border != "") {
  1655. $img->setborder($border);
  1656. $img->setstyle("border-style:solid;border-width:" . $border . "px;");
  1657. if ($bdcolor != "") $img->setstyle("border-color:$bdcolor;");
  1658. }
  1659. if ($align != "") $img->setalign($align);
  1660. if ($pad != "") {
  1661. $img->sethspace($pad);
  1662. $img->setvspace($pad);
  1663. }
  1664. $new_content = $img->render();
  1665. }
  1666. }
  1667. break;
  1668. // MEDIA or DOCUMENT
  1669. case "media":
  1670. case "document":
  1671. $new_content = "";
  1672. $catid = $attributes["id"];
  1673. $display = $attributes["display"];
  1674. $width = $attributes["width"];
  1675. $height = $attributes["height"];
  1676. if ($mediatype == "media") {
  1677. $autostart = ($attributes["autostart"] == "yes");
  1678. $loop = ($attributes["loop"] == "yes");
  1679. $showcontrols = ($attributes["showcontrols"] == "yes");
  1680. }
  1681. if ($width == 0 || $width == "") $width = 200;
  1682. if ($height == 0 || $height == "") $height = 200;
  1683. $tooltip = $attributes["title"];
  1684. if ($catid != "") {
  1685. $qQ = dbrecordset("SELECT * FROM ax_catalog WHERE cat_id=$catid");
  1686. if ($qQ->hasdata) {
  1687. $src = $qQ->field("filepath");
  1688. $category = $qQ->field("mime_category");
  1689. switch ($category) {
  1690. case "movie":
  1691. $media = new MediaObject($src, $width, $height, $autostart, $loop, $showcontrols);
  1692. switch ($display) {
  1693. case "icon": $media->AsIcon($tooltip); break;
  1694. case "link": $media->AsLink($tooltip); break;
  1695. }
  1696. break;
  1697. case "audio":
  1698. $media = new MediaObject($src, $width, $height, $autostart, $loop, $showcontrols);
  1699. switch ($display) {
  1700. case "icon": $media->AsIcon($tooltip); break;
  1701. case "link": $media->AsLink($tooltip); break;
  1702. }
  1703. break;
  1704. case "flash":
  1705. $media = new FlashObject($src, $width, $height, $autostart, $loop);
  1706. switch ($display) {
  1707. case "icon": $media->AsIcon($tooltip); break;
  1708. case "link": $media->AsLink($tooltip); break;
  1709. }
  1710. break;
  1711. case "document":
  1712. $media = new DocumentObject($src, $width, $height);
  1713. switch ($display) {
  1714. case "icon": $media->AsIcon($tooltip); break;
  1715. case "link": $media->AsLink($tooltip, "_new"); break;
  1716. }
  1717. break;
  1718. } // switch
  1719. if (is_object($media)) {
  1720. $new_content = $media->render();
  1721. }
  1722. }
  1723. }
  1724. break;
  1725. }// switch
  1726. } // got attributes
  1727. // Replace data tag with new content..
  1728. $new_content = str_replace("<img ", "<AXYL_IMAGE ", $new_content);
  1729. $content = str_replace($datatag, $new_content, $content);
  1730. }
  1731. } // while
  1732.  
  1733. // Return the processed content..
  1734. $content = str_replace("<AXYL_IMAGE ", "<img ", $content);
  1735. return $content;
  1736.  
  1737. } // expanded_content
  1738. // ....................................................................
  1739. /**
  1740. * Render the blocklet.
  1741. * @return string The HTML
  1742. */
  1743. function html() {
  1744. debug_trace($this);
  1745.  
  1746. $s = "";
  1747.  
  1748. // Main Blocklet Table
  1749. $btable = new table("BKT_$this->blockletid");
  1750.  
  1751. // Set table width if specified..
  1752. if ($this->width != "") {
  1753. $btable->setwidth($this->width . "%");
  1754. }
  1755.  
  1756. if ($RESPONSE->browser != BROWSER_NETSCAPE) {
  1757. $btable->setalign($this->justify);
  1758. }
  1759.  
  1760. // TOP RULER
  1761. if ($this->ruler == "top") {
  1762. $btable->tr();
  1763. $rul = new hr("$this->ruler_width%", $this->ruler_size, $this->ruler_colour);
  1764. $btable->td( $rul->render() );
  1765. $btable->td_alignment($this->justify);
  1766. }
  1767.  
  1768. // HEADING
  1769. if ($this->heading != "") {
  1770. $HTAG = "h$this->heading_level";
  1771. $btable->tr();
  1772. $btable->td("<$HTAG>" . $this->heading . "</$HTAG>");
  1773. $btable->td_alignment($this->justify);
  1774. if ($this->heading_colour != "") {
  1775. $btable->td_contentcss("color:$this->heading_colour");
  1776. }
  1777. }
  1778.  
  1779. // CONTENT
  1780. // First, expand any special tags..
  1781. $content = $this->expanded_content();
  1782.  
  1783. // Now, render the content..
  1784. if ($content != "") {
  1785. $btable->tr();
  1786. // Format the content..
  1787. $scell = $this->format_content(
  1788. $content,
  1789. $this->type,
  1790. $this->content_css()
  1791. );
  1792. // Add the blocklet content to the table..
  1793. $btable->td($scell);
  1794. $btable->td_alignment($this->justify);
  1795. } // if got content
  1796.  
  1797. // BOTTOM RULER
  1798. if ($this->ruler == "bottom") {
  1799. $btable->tr();
  1800. $rul = new hr("$this->ruler_width%", $this->ruler_size, $this->ruler_colour);
  1801. $btable->td( $rul->render() );
  1802. $btable->td_alignment($this->justify);
  1803. }
  1804.  
  1805. // END TABLE DIV
  1806. $s .= $btable->render();
  1807.  
  1808. debug_trace();
  1809. // Return the HTML..
  1810. return $s;
  1811. } // html
  1812.  
  1813.  
  1814.  
  1815. } // blocklet class
  1816. // ----------------------------------------------------------------------
  1817.  
  1818. /** Utility function to extract content attributes from string.
  1819. * Incoming Format is:
  1820. * <tagname attrname="attrvalue" attrname="attrvalue" ... >
  1821. * Returns an associative array:
  1822. * An element 'tagname' will contain the tag name:
  1823. * returnedarray["tagname"] = tagname
  1824. * Other elements one for each attribute:
  1825. * returnedarray["attrname"] = attrvalue
  1826. * @access private
  1827. */
  1828. function extractAttributes($str){
  1829. $attrs = array();
  1830. if (preg_match("/<(.*?) (.*?)>/i", $str, $matches) ) {
  1831. $attrs["tagname"] = $matches[1];
  1832. $attributes = trim($matches[2]);
  1833. if (preg_match_all("/(.*?)=\"(.*?)\"/i", $attributes, $matches)) {
  1834. $total = count($matches[0]);
  1835. for ($tagno = 0; $tagno < $total; $tagno++) {
  1836. if (trim($matches[1][$tagno]) != "") {
  1837. $attrname = trim(strtolower($matches[1][$tagno]));
  1838. $attrval = trim($matches[2][$tagno]);
  1839. $attrs[$attrname] = $attrval;
  1840. }
  1841. }
  1842. }
  1843. }
  1844. return $attrs;
  1845. } // extractAttributes
  1846. // ----------------------------------------------------------------------
  1847.  
  1848. ?>

Documentation generated by phpDocumentor 1.3.0RC3