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='" . escape_string($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='" . escape_string($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='" . escape_string($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 a search engine, if Search Engine
  512. * indexing is enabled (via the configvalue 'Search Engine Host'). This has
  513. * no effect 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, $SE_AVAILABLE;
  525. debug_trace($this);
  526. if ($SE_AVAILABLE) {
  527. include_once("search-lucene-defs.php");
  528. include_once("search-index-defs.php");
  529. // Read content from DB since it may have just been saved..
  530. $q = "SELECT b.heading, b.content, b.blocklet_desc";
  531. $q .= " FROM ax_block_blocklet bb, ax_blocklet b";
  532. $q .= " WHERE bb.block_id=$this->blockid";
  533. $q .= " AND b.blocklet_id=bb.blocklet_id";
  534. $bQ = dbrecordset($q);
  535. $allcontent = array();
  536. $allcontent[] = $RESPONSE->head->title;
  537. $allcontent[] = $this->block_desc;
  538. if ($bQ->hasdata) {
  539. do {
  540. $allcontent[] = $bQ->field("heading");
  541. $allcontent[] = $bQ->field("content");
  542. $bkt_desc = $bQ->field("blocklet_desc");
  543. if ($bkt_desc != "(enter a blocklet description)") {
  544. $allcontent[] = $bkt_desc;
  545. }
  546. } while ($bQ->get_next());
  547. }
  548. $I = new searchengine_indexer();
  549. $I->index_field("category:Text", ($category == "" ? "sitecontent" : $category));
  550. $I->index_field("path:Text", $path);
  551. $I->index_field("title:Text", $title);
  552. $I->index_field("lastmodified:Date", time());
  553. if ($RESPONSE->multilang && $this->language > 0) {
  554. $I->index_field("language:Text", $this->language);
  555. }
  556. // Add in any metadata fields being supplied..
  557. if ($metadata !== false && count($metadata->metadata_elements) > 0) {
  558. foreach ($metadata->metadata_elements as $element_id => $element) {
  559. if ($element->tag_name != "" && $element->tag_value != "") {
  560. $I->index_field($element->tag_name . ":Text", $element->tag_value);
  561. }
  562. }
  563. }
  564. $I->index_content("AXYLBLOCKID_$this->blockid", implode(" ", $allcontent));
  565. $I->execute();
  566. }
  567. debug_trace();
  568. } // index
  569. // ....................................................................
  570. /**
  571. * Un-index the block.
  572. * Un-index this block from the search engine, if indexing is enabled (via
  573. * the configvalue 'Search Engine Host'). This has no effect if you are
  574. * not using the Axyl framework.
  575. */
  576. function unindex() {
  577. global $SE_AVAILABLE;
  578. debug_trace($this);
  579. // Deal with indexing if enabled. In this case we then use the unique
  580. // block_id as the index ID, and unindex from the search engine
  581. // so that references to this block are removed.
  582. if ($SE_AVAILABLE) {
  583. include_once("search-lucene-defs.php");
  584. include_once("search-index-defs.php");
  585. $UI = new searchengine_unindexer();
  586. $UI->unindex("AXYLBLOCKID_$this->blockid");
  587. $UI->execute();
  588. }
  589. debug_trace();
  590. } // unindex
  591. // ....................................................................
  592. /**
  593. * Render the Wysiwyg editing suite.
  594. * @return string The HTML for the editing suite form etc.
  595. * @access private
  596. */
  597. function wysiwyg_editform($lang_encoding, $lang_direction) {
  598. $this->activate_editing();
  599. return $this->blockeditor->wysiwyg_editform($lang_encoding, $lang_direction);
  600. } // wysiwyg_editform
  601. // ....................................................................
  602. /**
  603. * Render the block editing suite.
  604. * @return string The HTML for the editing suite form etc.
  605. * @access private
  606. */
  607. function block_editform($lang_encoding, $lang_direction) {
  608. $this->activate_editing();
  609. return $this->blockeditor->block_editform($lang_encoding, $lang_direction);
  610. } // block_editform
  611. // ....................................................................
  612. /**
  613. * Render the block content.
  614. * @return string The HTML
  615. * @access private
  616. */
  617. function blockcontent($lang_encoding, $lang_direction) {
  618. debug_trace($this);
  619. global $LIBDIR;
  620. global $RESPONSE;
  621. $editing = false;
  622.  
  623. $s = "";
  624.  
  625. // Render the blocklets in a table..
  626. $Tvw = new table($this->blockid);
  627.  
  628. // Apply supplemental style, if given..
  629. if ($this->block_style != "") {
  630. $Tvw->setstyle($this->block_style);
  631. }
  632.  
  633. // Apply background image if there is one..
  634. if ($this->background_img != NULLVALUE) {
  635. $qQ = dbrecordset("SELECT * FROM ax_catalog WHERE cat_id=$this->background_img");
  636. if ($qQ->hasdata) {
  637. $src = $qQ->field("filepath");
  638. $Tvw->setbackground($src);
  639. }
  640. }
  641.  
  642. // Apply border styles, if we have a border..
  643. $bdrstyle = "";
  644. if ($this->border_width > 0) {
  645. $bdrstyle = "border-width:" . $this->border_width . "px;";
  646. $bdrstyle .= "border-color:" . $this->border_colour . ";";
  647. $bdrstyle .= "border-style:solid;";
  648. $Tvw->setstyle($bdrstyle);
  649. }
  650.  
  651. if ($this->mode != "previewing" && $RESPONSE->ismemberof_group_in( array_merge($this->editor_groups, $this->author_groups) )) {
  652. $editor = true;
  653. if ($bdrstyle == "") {
  654. $Tvw->setstyle("border-width:1px;border-style:dotted;border-color:#ff0000;");
  655. }
  656. // Tools for the toolbar
  657. $toolbar = array();
  658. if ($this->user_can_edit()) {
  659. $toolbar[] = new form_imagebutton("_edit", "", "", "$LIBDIR/img/_edit.gif", "Edit block", 42, 15);
  660. }
  661.  
  662. // Toolbar table
  663. $Tbar = new table("toolbar");
  664. $Tbar->tr("axtitle");
  665. $Tbar->th("[Block]", "axtitle");
  666. $Tbar->th_alignment("", "top");
  667. $tools = "";
  668. foreach ($toolbar as $tool) {
  669. $tools .= $tool->render();
  670. }
  671. $Tbar->th($tools, "axtitle");
  672. $Tbar->th_css("text-align:right");
  673.  
  674. // Put toolbar into table..
  675. $Tvw->tr("axtitle");
  676. $Tvw->td( $Tbar->render(), "axtitle" );
  677. }
  678.  
  679. // Generate an ordered array of our visible blocklets..
  680. if (isset($this->blocklets)) {
  681. $ordblocklets = array();
  682. foreach ($this->blocklets as $blocklet) {
  683. if ($blocklet->visible) {
  684. $ordblocklets[$blocklet->blockletid] = $blocklet->display_order;
  685. }
  686. }
  687. asort($ordblocklets, SORT_NUMERIC);
  688. $visible_blocklets = array();
  689. foreach($ordblocklets as $blockletid => $order) {
  690. $visible_blocklets[] = $blockletid;
  691. }
  692.  
  693. // Ascertain blocklet display metrics..
  694. $tot_blocklets = count($visible_blocklets);
  695. $tot_rows = ceil($tot_blocklets / $this->cols);
  696.  
  697. // Render the blocklets..
  698. $Tvw->tr();
  699. $Tvw->td();
  700. $Tvw->td_alignment("", "top");
  701.  
  702. $Tbl = new table("B" . $this->blockid);
  703. if ($this->background_colour != "") {
  704. $Tbl->setbgcolor($this->background_colour);
  705. }
  706. $Tbl->tr();
  707. $bc = 0;
  708. $col = 1;
  709. $widthpct = floor(100 / $this->cols);
  710. foreach ($visible_blocklets as $blockletid) {
  711. $blocklet = $this->blocklets[$blockletid];
  712. if ($bc++ % $tot_rows == 0) {
  713. if (isset($Tcol)) {
  714. // Put the last blocklets column in..
  715. $Tbl->td_content($Tcol->render());
  716. unset($Tcol);
  717.  
  718. // If multi-column and guttering enabled, make a
  719. // gutter column here..
  720. if ($this->cols > 1 && $this->gutter_width > 0) {
  721. $gutc = (($this->gutter_colour != "") ? $this->gutter_colour : "black");
  722. $Tbl->td();
  723. //$Tbl->td_metrics($this->gutter_width);
  724. $guts .= "border-right:" . $this->gutter_width . "px ";
  725. $guts .= " solid";
  726. $guts .= " $this->gutter_colour;";
  727. $Tbl->td_css($guts);
  728. }
  729. }
  730. // Make new cell for next column..
  731. $Tbl->td();
  732. $Tbl->td_alignment("", "top");
  733. if ($bc == $tot_blocklets) $widthpct += 1;
  734. $Tbl->td_metrics("$widthpct%");
  735. $Tcol = new table("B" . $this->blockid . "_" . $col++);
  736. }
  737. $Tcol->tr();
  738. $Tcol->td($blocklet->html());
  739. if ($this->blocklet_sep > 0 && $tot_blocklets > 1 && $bc < $tot_blocklets) {
  740. $Tcol->tr();
  741. $Tcol->td();
  742. $Tcol->td_height($this->blocklet_sep);
  743. }
  744. }
  745. if (isset($Tcol)) {
  746. $Tbl->td_content($Tcol->render());
  747. }
  748. $Tvw->td_content( $Tbl->render() );
  749. }
  750.  
  751. // Render the content table..
  752. $s .= $Tvw->render();
  753.  
  754. debug_trace();
  755. // Return the html..
  756. return $s;
  757. } // blockcontent
  758.  
  759. // ....................................................................
  760. /**
  761. * Render the block content as a CSV formatted stream. This is designed
  762. * to facilitate the exporting of complex tables of data as CSV format
  763. * for importing into spreadsheets, or databases etc.
  764. * @return string The content in CSV format.
  765. */
  766. function csv() {
  767. debug_trace($this);
  768. $s = "";
  769. // Generate an ordered array of our visible blocklets..
  770. if (isset($this->blocklets)) {
  771. $ordblocklets = array();
  772. foreach ($this->blocklets as $blocklet) {
  773. if ($blocklet->visible) {
  774. $ordblocklets[$blocklet->blockletid] = $blocklet->display_order;
  775. }
  776. }
  777. asort($ordblocklets, SORT_NUMERIC);
  778. $visible_blocklets = array();
  779. while (list($blockletid, $order) = each($ordblocklets)) {
  780. $visible_blocklets[] = $blockletid;
  781. }
  782. foreach ($visible_blocklets as $blockletid) {
  783. $blocklet = $this->blocklets[$blockletid];
  784. $s .= $blocklet->csv() . "\n";
  785. }
  786. }
  787. debug_trace();
  788. // Return the csv stream..
  789. return $s;
  790. } // csv
  791.  
  792. // ....................................................................
  793. /**
  794. * Render the block content according to the mode of operation
  795. * we are in. Possible modes: 'viewing', 'editing', 'saving'.
  796. * @return string The HTML
  797. */
  798. function html() {
  799. debug_trace($this);
  800. global $LIBDIR;
  801. global $RESPONSE;
  802. global $edit_blockid;
  803.  
  804. // Language details..
  805. $lang_encoding = "";
  806. $lang_direction = "";
  807. $language = $this->language;
  808. if ($RESPONSE->multilang) {
  809. if ($this->language != 0) {
  810. $lang_encoding = $this->lang_encoding;
  811. $lang_direction = $this->lang_direction;
  812. }
  813. else {
  814. if ($this->layout_language != 0) {
  815. $language = $this->layout_language;
  816. $lang_encoding = $this->layout_lang_encoding;
  817. $lang_direction = $this->layout_lang_direction;
  818. }
  819. }
  820. // Make sure RESPONSE takes note of language setting. If this
  821. // language was already added, it doesn't matter..
  822. if ($language != 0) {
  823. $RESPONSE->add_language($language);
  824. }
  825. }
  826.  
  827. $s = "";
  828. // Start form for editing..
  829. if ($this->exportable || $RESPONSE->ismemberof_group_in( array_merge($this->editor_groups, $this->author_groups) )) {
  830. $s .= "<form name=\"$this->blockfm\" method=\"post\" enctype=\"multipart/form-data\">";
  831. }
  832.  
  833. switch($this->mode) {
  834. case "editing":
  835. // Make sure edit request is meant for us..
  836. if (!isset($edit_blockid) || $edit_blockid != $this->blockid) {
  837. return "";
  838. }
  839. // Deal with first block edit. In this case it won't yet
  840. // exist in the database, so we create it here..
  841. if (!$this->exists) {
  842. $this->put();
  843. }
  844. $this->mode = "saving";
  845. // Show the appropriate editing form..
  846. switch ($this->block_type) {
  847. case WYSIWYG_EDITOR:
  848. $s .= $this->wysiwyg_editform($lang_encoding, $lang_direction);
  849. break;
  850. default:
  851. $s .= $this->block_editform($lang_encoding, $lang_direction);
  852. } // switch
  853. break;
  854.  
  855. default:
  856. if ($this->mode != "viewing" && $this->mode != "previewing") {
  857. $this->mode = "viewing";
  858. }
  859. $s .= $this->blockcontent($lang_encoding, $lang_direction);
  860. if ($this->exportable) {
  861. $expbtn = new form_imagebutton("_exportblock");
  862. $expbtn->setimage("$LIBDIR/img/_export.gif", "Export this information in CSV format");
  863. $s .= "<p>" . $expbtn->render() . "</p>";
  864. }
  865. } // switch
  866.  
  867. // Finish the form..
  868. if ($this->exportable || $RESPONSE->ismemberof_group_in( array_merge($this->editor_groups, $this->author_groups) )) {
  869. // Include action hidden field, and block ID
  870. $mode = new form_hiddenfield("blockmode", $this->mode);
  871. $blid = new form_hiddenfield("edit_blockid", $this->blockid);
  872. $s .= $mode->render() . $blid->render();
  873. // Layout version hidden field
  874. if ($this->layout_version != VERSION_UNDEFINED) {
  875. $lvers = new form_hiddenfield("layout_version", $this->layout_version);
  876. $lvcnt = new form_hiddenfield("layout_version_count", $this->layout_version_count);
  877. $s .= $lvers->render() . $lvcnt->render();
  878. }
  879. $s .= "</form>\n";
  880. }
  881.  
  882. return $s;
  883. } // html
  884. // ....................................................................
  885. /**
  886. * Process a block edit form POST.
  887. * Assume that the fields have been submitted in a form as named
  888. * in the config, and grab the POSTed values. This method is executed
  889. * from the constructor usually, before anything is read in from
  890. * the database. We get first shot to change data here.
  891. * @param text $id The identity of the set to update from POST
  892. * @access private
  893. */
  894. function POSTprocess() {
  895. debug_trace($this);
  896. global $RESPONSE, $LIBDIR;
  897. global $edit_blockid;
  898.  
  899. if (isset($edit_blockid) && $edit_blockid == $this->blockid) {
  900. global $_done_x, $_edit_x, $_exportblock_x, $blockmode;
  901. $this->mode = $blockmode;
  902. switch ($this->mode) {
  903. case "viewing":
  904. // Check for editing mode..
  905. if (isset($_edit_x)) {
  906. $this->mode = "editing";
  907. }
  908. // Check for user export button-press. In this
  909. // case we deliver CSV content, and exit..
  910. elseif (isset($_exportblock_x)) {
  911. $exptitle = $RESPONSE->body->title;
  912. if ($exptitle == "") {
  913. $exptitle = $this->blockid;
  914. }
  915. $this->get();
  916. $csv = $this->csv();
  917. $RESPONSE->discard();
  918. $RESPONSE->set_encoding("", "text/csv");
  919. header("Content-Disposition: attachment; filename=$exptitle.csv");
  920. echo $csv;
  921. exit;
  922. }
  923. break;
  924.  
  925. case "saving":
  926. if ($edit_blockid == $this->blockid) {
  927. global $_csvimport_x, $blocklet_id;
  928. global $_save_x, $_cancel_x, $_done_x;
  929. global $_wysiwygpost_form;
  930. global $_recmaintpost_form;
  931. global $_recmaintpost_data;
  932. global $_recmaintpost_flds;
  933. global $_recmaintpost_dels;
  934. global $_recmaintpost_order;
  935.  
  936. // Let me out of here..
  937. if (isset($_done_x) || isset($_cancel_x)) {
  938. // Drop through to viewing..
  939. $this->mode = "viewing";
  940. }
  941. // Posted record maintenance data..
  942. elseif ( isset($_recmaintpost_form)
  943. && $_recmaintpost_form == $this->blockfm) {
  944. // Posted CSV table data. This data is to be appended to
  945. // the blocklet content as a table..
  946. if (isset($_csvimport_x) && isset($blocklet_id)) {
  947. $up = new fileupload();
  948. if ($up->uploaded_count >= 1) {
  949. // Process a uploaded file(s)..
  950. $file_mime = $up->mimetype;
  951. if ($file_mime != CONTENT_CSV) {
  952. $file_mime = mimetype_from_filename($up->filename);
  953. }
  954. if ($file_mime == CONTENT_CSV) {
  955. // Process the file..
  956. $fup = new csv_inputfile($up->filepath);
  957. $tablerow = false;
  958. $newtable = "";
  959. if ($fup->opened) {
  960. do {
  961. $tablerow = $fup->readln();
  962. if ($tablerow) {
  963. $newtable .= implode("|", $tablerow) . "\n";
  964. }
  965. } while ($tablerow);
  966. $fup->closefile();
  967. if ($newtable != "") {
  968. $ob = dbrecordset("SELECT content FROM ax_blocklet WHERE blocklet_id=$blocklet_id");
  969. if ($ob->hasdata) {
  970. $orig_content = $ob->field("content");
  971. if ($orig_content != "") $orig_content .= "\n";
  972. $ub = new dbupdate("ax_blocklet");
  973. $ub->set("content", $orig_content . $newtable);
  974. $ub->set("blocklet_type", "table");
  975. $ub->where("blocklet_id=$blocklet_id");
  976. $ub->execute();
  977. }
  978. }
  979. }
  980. else {
  981. $emsg = "failed to open uploaded file: '$up->filename'";
  982. $errmsgs[] = $emsg;
  983. debugbr($emsg, DBG_DEBUG);
  984. }
  985. }
  986. else {
  987. $emsg = "Not a comma-separated variable (CSV) file: '$up->filename'";
  988. $errmsgs[] = $emsg;
  989. debugbr($emsg, DBG_DEBUG);
  990. }
  991. }
  992. else {
  993. $emsg = "Nothing was uploaded.";
  994. $errmsgs[] = $emsg;
  995. debugbr($emsg, DBG_DEBUG);
  996. }
  997. // Drop through to viewing..
  998. $this->mode = "editing";
  999.  
  1000. } // if CSV import
  1001.  
  1002. else {
  1003. // Deal with Save, Delete, Re-ordering etc..
  1004. if (isset($_recmaintpost_dels) && $_recmaintpost_dels != "") {
  1005. $blocklet_delids = explode(FIELD_DELIM, $_recmaintpost_dels);
  1006. foreach ($blocklet_delids as $delblockletid) {
  1007. dbcommand("DELETE FROM ax_blocklet WHERE blocklet_id=$delblockletid");
  1008. }
  1009. }
  1010. // Blocklet adds and saves..
  1011. if (isset($_recmaintpost_data) && $_recmaintpost_data != "") {
  1012. $blockletrecs = explode(RECORD_DELIM, $_recmaintpost_data);
  1013. $blocklet_fields = explode(",", $_recmaintpost_flds);
  1014. foreach ($blockletrecs as $blockletrec) {
  1015. $blocklet_values = explode(FIELD_DELIM, $blockletrec);
  1016. $blockletid = array_shift($blocklet_values);
  1017. // Cater for new creations..
  1018. if (strstr($blockletid, "NEW_")) {
  1019. $savedid = $blockletid;
  1020. $blockletid = get_next_sequencevalue("seq_blocklet_id", "ax_blocklet", "blocklet_id");
  1021. $ib = new dbinsert("ax_blocklet");
  1022. $ib->set("blocklet_id", $blockletid);
  1023. $ib->execute();
  1024. $ibb = new dbinsert("ax_block_blocklet");
  1025. $ibb->set("block_id", $this->blockid);
  1026. $ibb->set("blocklet_id", $blockletid);
  1027. $ibb->set("display_order", 99);
  1028. $ibb->execute();
  1029. // Fix up potential re-ordering id..
  1030. if (isset($_recmaintpost_order)) {
  1031. $_recmaintpost_order = str_replace("$savedid", "$blockletid", $_recmaintpost_order);
  1032. }
  1033. }
  1034. // Update the blocklet data..
  1035. $bu = new dbupdate("ax_blocklet");
  1036. $bu->where("blocklet_id=$blockletid");
  1037. $pos = 0;
  1038. foreach ($blocklet_fields as $blocklet_field) {
  1039. if ($blocklet_field == "visible") {
  1040. $visible_value = $blocklet_values[$pos++];
  1041. }
  1042. else {
  1043. $bu->set($blocklet_field, $blocklet_values[$pos++]);
  1044. }
  1045. }
  1046. $bu->execute();
  1047. // Now save the visibility flag..
  1048. if (isset($visible_value)) {
  1049. $bu = new dbupdate("ax_block_blocklet");
  1050. $bu->where("block_id=$this->blockid AND blocklet_id=$blockletid");
  1051. $bu->set("visible", ($visible_value == "t"));
  1052. $bu->execute();
  1053. }
  1054. } // foreach blockletrecs
  1055. }
  1056.  
  1057. // Save block properties..
  1058. global $block_desc, $language, $block_style;
  1059. global $cols, $gutter_width, $gutter_colour;
  1060. global $background_colour, $background_img;
  1061. global $block_justify, $block_valign;
  1062. global $block_border_width, $block_border_colour;
  1063. global $blocklet_sep, $block_exportable;
  1064. if (isset($cols) && $cols > 0) {
  1065. $bu = new dbupdate("ax_block");
  1066. $bu->where("block_id=$this->blockid");
  1067. $bu->set("block_desc", $block_desc);
  1068. $bu->set("lang_id", $language);
  1069. $bu->set("cols", $cols);
  1070. $bu->set("gutter_width", $gutter_width);
  1071. $bu->set("gutter_colour", $gutter_colour);
  1072. $bu->set("blocklet_sep", $blocklet_sep);
  1073. $bu->set("background_colour", $background_colour);
  1074. $bu->set("background_img", $background_img);
  1075. $bu->set("justify", $block_justify);
  1076. $bu->set("valign", $block_valign);
  1077. $bu->set("border_width", $block_border_width);
  1078. $bu->set("border_colour", $block_border_colour);
  1079. $bu->set("block_style", $block_style);
  1080. $bu->set("exportable", isset($block_exportable));
  1081. $bu->execute();
  1082. }
  1083.  
  1084. // Check/save blocklet ordering..
  1085. if (isset($_recmaintpost_order) && $_recmaintpost_order != "") {
  1086. $ord = 1;
  1087. $idlist = explode(FIELD_DELIM, $_recmaintpost_order);
  1088. foreach ($idlist as $blockletid) {
  1089. $upd = new dbupdate("ax_block_blocklet");
  1090. $upd->where("block_id=$this->blockid AND blocklet_id=$blockletid");
  1091. $upd->set("display_order", $ord);
  1092. $upd->execute();
  1093. $ord += 1;
  1094. }
  1095. }
  1096.  
  1097. // Index the block with current webpage path and title..
  1098. global $layout_version, $layout_version_count;
  1099. if (!isset($layout_version) ||
  1100. $layout_version == VERSION_LIVE ||
  1101. $layout_version_count == 1) {
  1102. debugbr("indexing saved block. Layout ver=$layout_version", DBG_DEBUG);
  1103. $this->get();
  1104. $this->index($RESPONSE->requested, $RESPONSE->head->title);
  1105. }
  1106.  
  1107. // Drop through to viewing..
  1108. $this->mode = "viewing";
  1109. }
  1110. }
  1111. // Is it a wysiwyg post..
  1112. elseif ( isset($_wysiwygpost_form)
  1113. && $_wysiwygpost_form == $this->blockfm) {
  1114. global $wysiwyg_content;
  1115. $this->get();
  1116. $bb = current($this->blocklets);
  1117. if (isset($bb) && isset($bb->blockletid)) {
  1118. $bbup = new dbupdate("ax_blocklet");
  1119. $bbup->set("content", $wysiwyg_content);
  1120. $bbup->where("blocklet_id=$bb->blockletid");
  1121. $bbup->execute();
  1122. $this->blocklets[$bb->blockletid] = $bb;
  1123. }
  1124. // Also save some of the block properties..
  1125. global $block_desc, $block_style;
  1126. global $background_colour, $background_img;
  1127. global $block_justify, $block_valign;
  1128. global $block_border_width, $block_border_colour;
  1129. $bu = new dbupdate("ax_block");
  1130. $bu->where("block_id=$this->blockid");
  1131. $bu->set("block_desc", $block_desc);
  1132. $bu->set("background_colour", $background_colour);
  1133. $bu->set("background_img", $background_img);
  1134. $bu->set("justify", $block_justify);
  1135. $bu->set("valign", $block_valign);
  1136. $bu->set("border_width", $block_border_width);
  1137. $bu->set("border_colour", $block_border_colour);
  1138. $bu->set("block_style", $block_style);
  1139. $bu->execute();
  1140.  
  1141. // Index the block with current webpage path and title..
  1142. global $layout_version, $layout_version_count;
  1143. if (!isset($layout_version) ||
  1144. $layout_version == VERSION_LIVE ||
  1145. $layout_version_count == 1) {
  1146. debugbr("indexing saved wysiwyg block. Layout ver=$layout_version", DBG_DEBUG);
  1147. $this->get();
  1148. $this->index($RESPONSE->requested, $RESPONSE->head->title);
  1149. }
  1150. }
  1151. }
  1152. break;
  1153. } // switch
  1154. }
  1155. // If the user preference says so, then set the mode to
  1156. // content preview mode..
  1157. $prefs = new configuration("preferences", $RESPONSE->userid);
  1158. if ($prefs->field_exists("Content Preview Mode")) {
  1159. if ($prefs->value("Content Preview Mode") === true) {
  1160. $this->mode = "previewing";
  1161. }
  1162. }
  1163. debug_trace();
  1164. } // POSTprocess
  1165.  
  1166.  
  1167.  
  1168. } // block class
  1169. // ----------------------------------------------------------------------
  1170.  
  1171. /**
  1172. * The blocklet is simply a part of a block. It is almost a 'paragraph' of
  1173. * content, excepting that a blocklet might have content of several text
  1174. * paragraphs, so it is something slightly different, hence the name. This
  1175. * class knows how to get, save and delete blocklets, and how to render
  1176. * them as html.
  1177. * @package cm
  1178. */
  1179. class blocklet extends RenderableObject {
  1180. /** blocklet ID */
  1181.  
  1182. var $blockletid;
  1183. /** Whether blocklet exists in database */
  1184.  
  1185. var $exists = false;
  1186. /** The description of the current blocklet */
  1187.  
  1188. var $desc = "";
  1189. /** The blocklet type: 'text', 'list', 'ordered', 'bullets', or 'table' */
  1190.  
  1191. var $type = "text";
  1192. /** The width % of the blocklet table */
  1193.  
  1194. var $width = 100;
  1195. /** Justification: 'left', 'right', 'centered' */
  1196.  
  1197. var $justify = "left";
  1198. /** blocklet heading */
  1199.  
  1200. var $heading;
  1201. /** blocklet heading level (1-6) */
  1202.  
  1203. var $heading_level = 3;
  1204. /** Heading colour */
  1205.  
  1206. var $heading_colour = "";
  1207. /** blocklet ruler: 'none', 'top', 'bottom' */
  1208.  
  1209. var $ruler = "none";
  1210. /** Ruler width percent: 0-100 */
  1211.  
  1212. var $ruler_width = 100;
  1213. /** Ruler pixel size */
  1214.  
  1215. var $ruler_size = 1;
  1216. /** Ruler colour */
  1217.  
  1218. var $ruler_colour = "";
  1219. /** Blocklet textual content */
  1220.  
  1221. var $content = "";
  1222. /** Content size adjustment -2 thru +2 */
  1223.  
  1224. var $content_size = 0;
  1225. /** Content colour */
  1226.  
  1227. var $content_colour = "";
  1228. /** Manual style to apply to content */
  1229.  
  1230. var $blocklet_style = "";
  1231. /** Table style to apply to content */
  1232.  
  1233. var $table_style = "";
  1234. /** True if we autojustify table */
  1235.  
  1236. var $table_autojustify = false;
  1237. /** True if we autojustify table */
  1238.  
  1239. var $table_rowstripes = false;
  1240. /** Whether blocklet is visible */
  1241.  
  1242. var $visible = true;
  1243. /** Display order of this blocklet */
  1244.  
  1245. var $display_order = 1;
  1246. // ....................................................................
  1247. /**
  1248. * Constructor
  1249. * Create a new blocklet object.
  1250. * @param string $id The unique identity of the blocklet.
  1251. */
  1252. function blocklet($id=NEW_BLOCKLET) {
  1253. $this->blockletid = $id;
  1254. $this->get($id);
  1255.  
  1256. } // blocklet
  1257. // ....................................................................
  1258. /**
  1259. * Get the blocklet.
  1260. * Retrieves the specified blocklet from database.
  1261. * @param string $id The unique integer identity of the blocklet to get.
  1262. */
  1263. function get($id) {
  1264. debug_trace($this);
  1265. $this->exists = false;
  1266. if ($id != NEW_BLOCKLET) {
  1267. // Try and read in existing blocklet info..
  1268. $q = "SELECT * FROM ax_blocklet";
  1269. $q .= " WHERE blocklet_id=$id";
  1270. $blq = dbrecordset($q);
  1271. if ($blq->hasdata) {
  1272. $this->blocklet_desc = $blq->field("blocklet_desc");
  1273. $this->type = $blq->field("blocklet_type");
  1274. $this->justify = $blq->field("justify");
  1275. $this->heading = $blq->field("heading");
  1276. $this->heading_level = $blq->field("heading_level");
  1277. $this->heading_colour = $blq->field("heading_colour");
  1278. $this->ruler = $blq->field("ruler");
  1279. $this->ruler_width = $blq->field("ruler_width");
  1280. $this->ruler_size = $blq->field("ruler_size");
  1281. $this->ruler_colour = $blq->field("ruler_colour");
  1282. $this->content = $blq->field("content");
  1283. $this->content_size = $blq->field("content_size");
  1284. $this->content_colour = $blq->field("content_colour");
  1285. $this->blocklet_style = $blq->field("blocklet_style");
  1286. $this->table_style = $blq->field("table_style");
  1287. $this->table_autojustify = $blq->istrue("table_autojustify");
  1288. $this->table_rowstripes = $blq->istrue("table_rowstripes");
  1289. $this->exists = true;
  1290. }
  1291. }
  1292. debug_trace();
  1293. // Return true if at least the blocklet exists..
  1294. return $this->exists;
  1295. } // get
  1296. // ....................................................................
  1297. /**
  1298. * Save the blocklet.
  1299. * Save this blocklet to the database. Create a new one if it
  1300. * doesn't already exist.
  1301. */
  1302. function put() {
  1303. debug_trace($this);
  1304. // Deal with brand new blocklet..
  1305. if (!$this->exists) {
  1306. // If we are in need of a new ID, then get one..
  1307. if ($this->blockletid == NEW_BLOCKLET) {
  1308. $this->blockletid = get_next_sequencevalue("seq_blocklet_id", "ax_blocklet", "blocklet_id");
  1309. }
  1310. $blq = new dbinsert("ax_blocklet");
  1311. $blq->set("blocklet_id", $this->blockletid);
  1312. }
  1313. else {
  1314. $blq = new dbupdate("ax_blocklet");
  1315. $blq->where("blocklet_id=$this->blockletid");
  1316. }
  1317. $blq->set("blocklet_desc", $this->blocklet_desc);
  1318. $blq->set("blocklet_type", $this->type);
  1319. $blq->set("justify", $this->justify);
  1320. $blq->set("heading", $this->heading);
  1321. $blq->set("heading_level", $this->heading_level);
  1322. $blq->set("heading_colour", $this->heading_colour);
  1323. $blq->set("ruler", $this->ruler);
  1324. $blq->set("ruler_width", $this->ruler_width);
  1325. $blq->set("ruler_size", $this->ruler_size);
  1326. $blq->set("ruler_colour", $this->ruler_colour);
  1327. $blq->set("content", $this->content);
  1328. $blq->set("content_size", $this->content_size);
  1329. $blq->set("content_colour", $this->content_colour);
  1330. $blq->set("blocklet_style", $this->blocklet_style);
  1331. $blq->set("table_style", $this->table_style);
  1332. $blq->set("table_autojustify", $this->table_autojustify);
  1333. $blq->set("table_rowstripes", $this->table_rowstripes);
  1334. $this->exists = $blq->execute();
  1335. debug_trace();
  1336. } // put
  1337. // ....................................................................
  1338. /**
  1339. * Delete the blocklet.
  1340. * Delete this blocklet from the database.
  1341. */
  1342. function delete() {
  1343. debug_trace($this);
  1344. // Don't assume RI wil delete the block_blocklets of this blocklet..
  1345. $del = new dbdelete("ax_block_blocklet");
  1346. $del->where("blocklet_id=$this->blockletid");
  1347. $del->execute();
  1348. $del = new dbdelete("ax_blocklet");
  1349. $del->where("blocklet_id=$this->blockletid");
  1350. $del->execute();
  1351. debug_trace();
  1352. } // delete
  1353. // ....................................................................
  1354. /**
  1355. * Content style.
  1356. * Returns an internal class style string based on the values of
  1357. * properties: content_colour and content_size. Returns the string
  1358. * as bare style specs 'font-size:0.8em;' etc.
  1359. * $access private
  1360. */
  1361. function content_css() {
  1362. $s = "";
  1363. if ($this->content_colour != "") {
  1364. $s .= "color:$this->content_colour;";
  1365. }
  1366. if ($this->content_size != 0) {
  1367. $em = number_format( (10 + $this->content_size)/10, 2);
  1368. $s .= "font-size:$em" . "em;";
  1369. }
  1370. if ($this->blocklet_style != "") {
  1371. $s .= $this->blocklet_style;
  1372. if (substr($this->blocklet_style, -1) != ";") {
  1373. $s .= ";";
  1374. }
  1375. }
  1376. return $s;
  1377. } // content_css
  1378. // ....................................................................
  1379. /**
  1380. * Content style.
  1381. * Returns an internal class style string based on the values of
  1382. * properties: content_colour and content_size. Returns the string
  1383. * as a full 'style="..." style, ready for a <span> tag etc..
  1384. * $access private
  1385. */
  1386. function content_style() {
  1387. $s = $this->content_css();
  1388. if ($s != "") $s = " style=\"$s\"";
  1389. return $s;
  1390. } // content_style
  1391. // ....................................................................
  1392. /**
  1393. * Format Content.
  1394. * Formats the given content according to the given content type.
  1395. * $access private
  1396. */
  1397. function format_content($content, $type="text", $css="") {
  1398. $s = "";
  1399. if (is_numeric($content)) $content = number_format($content);
  1400. switch ($type) {
  1401. // Vanilla list..
  1402. case "list":
  1403. $list = new vl($css);
  1404. $list->items = explode("\n", $content);
  1405. $s = $list->render();
  1406. break;
  1407. // Ordered list..
  1408. case "ordered":
  1409. $list = new ol($css);
  1410. $list->items = explode("\n", $content);
  1411. $s = $list->render();
  1412. break;
  1413. // Bullet points list..
  1414. case "bullets":
  1415. $list = new ul($css);
  1416. $list->items = explode("\n", $content);
  1417. $s = $list->render();
  1418. break;
  1419.  
  1420. case "table":
  1421. $t = new table("BKT_$this->blockletid");
  1422. if ($this->table_autojustify) {
  1423. $t->autojustify();
  1424. }
  1425. if ($this->table_rowstripes) {
  1426. $t->rowstripes("axyl_rowstripe_dark,axyl_rowstripe_lite");
  1427. }
  1428. $t->setpadding(2);
  1429. if ($this->table_style != "") {
  1430. $t->setcss($this->table_style);
  1431. }
  1432. // Assemble table..
  1433. $wprofile = "";
  1434. $rows = explode("\n", $content);
  1435. if (count($rows) > 0) {
  1436. foreach ($rows as $row) {
  1437. if (strstr($row, "~")) {
  1438. $wprofile = trim(str_replace("~", ",", $row));
  1439. }
  1440. else {
  1441. $t->tr();
  1442. // Heading rows use '^' separator..
  1443. if (strstr($row, "^")) {
  1444. $cells = explode("^", $row);
  1445. foreach ($cells as $cell) {
  1446. $t->th($cell);
  1447. $t->th_contentcss($css);
  1448. }
  1449. }
  1450. // Normal body rows use '|' separator..
  1451. else {
  1452. $cells = explode("|", $row);
  1453. foreach ($cells as $cell) {
  1454. $t->td($cell);
  1455. $t->td_alignment("", "top");
  1456. $t->td_contentcss($css);
  1457. }
  1458. }
  1459. }
  1460. } // foreach row
  1461. }
  1462. // Apply any width profile we got..
  1463. if ($wprofile != "") {
  1464. $t->set_width_profile($wprofile);
  1465. }
  1466. // Now put together the whole table..
  1467. $s .= $t->render();
  1468. break;
  1469.  
  1470. // Text content..
  1471. case "text":
  1472. // Paragraph content..
  1473. $style = $css;
  1474. if ($style != "") $style = " style=\"$style\"";
  1475. $para = "<p" . $style . ">";
  1476. $content = str_replace("\r\n\r\n", "$para", $content);
  1477. $s .= $para . $content;
  1478. break;
  1479.  
  1480. // Other content, raw content
  1481. default:
  1482. $s .= $content;
  1483. break;
  1484.  
  1485. } // switch
  1486.  
  1487. // Return content
  1488. return $s;
  1489. } // format_content
  1490.  
  1491. // ....................................................................
  1492. /**
  1493. * Render the blocklet as a CSV stream. We split the content types for
  1494. * this into 'table' and 'other'. For tables we use the "|" delimiter to
  1495. * determine where our commas go. For other content we basically just
  1496. * leave it as-is, only adding quotes.
  1497. * @return string The CSV formatted blocklet content.
  1498. */
  1499. function csv() {
  1500. debug_trace($this);
  1501. global $RESPONSE;
  1502.  
  1503. $content = strip_tags( $this->expanded_content() );
  1504. $content = str_replace("\r", "\n", $content);
  1505.  
  1506. // Format depending on type: 'text', 'list', 'ordered',
  1507. // 'bullets', or 'table'
  1508. switch ($this->type) {
  1509. case "table":
  1510. $rows = explode("\n", $content);
  1511. $content = "";
  1512. if (count($rows) > 0) {
  1513. foreach ($rows as $row) {
  1514. $csvrow = "";
  1515. if ($row != "" && $row != "\n" && !strstr($row, "~")) {
  1516. $row = str_replace("^", "|", $row);
  1517. $row = str_replace("\"", "\"\"", $row);
  1518. $bits = explode("|", $row);
  1519. $csvrow = "";
  1520. foreach ($bits as $bit) {
  1521. $csvrow .= "\"$bit\",";
  1522. }
  1523. $csvrow = substr($csvrow, 0, -1);
  1524. }
  1525. $content .= $csvrow;
  1526. if (substr($content, -1, 1) != "\n") {
  1527. $content .= "\n";
  1528. }
  1529. }
  1530. }
  1531. break;
  1532.  
  1533. default:
  1534. $content = str_replace("\"", "\"\"", $content);
  1535. $content = "\"$content\"";
  1536. break;
  1537. }
  1538. debug_trace();
  1539. // Return the CSV..
  1540. return $content;
  1541. } // csv
  1542. // ....................................................................
  1543. /**
  1544. * Process the current blocklet content for special tags. This effectively
  1545. * expands the special tags into 'real' content from database, or as image
  1546. * references etc. We return the expanded content as a string.
  1547. * @return string The new content, expanded as appropriate to the tags.
  1548. * $access private
  1549. */
  1550. function expanded_content() {
  1551. $content = $this->content;
  1552. $matches = array();
  1553. // NB: the original scheme for embedding Axyl content used object tags, however
  1554. // browsers didn't render these very well, so the current scheme uses img tags
  1555. // instead, whilst retaining a backward compatibility for existing websites.
  1556. $datapat = "/<object .*?axyl\/embedded-media.*?>|<img .*?axyl\/embedded-media.*?>/i";
  1557. while ( preg_match($datapat, $content, $matches) ) {
  1558. $datatag = $matches[0];
  1559. $attributes = extractAttributes($datatag);
  1560. if (!isset($attributes["name"])) {
  1561. $new_content = "";
  1562. $type = strtolower($attributes["type"]);
  1563. if (count($attributes) > 0 && $type == "axyl/embedded-media") {
  1564. $mediatype = strtolower($attributes["codetype"]);
  1565. switch ($mediatype) {
  1566. // DATA
  1567. case "data":
  1568. $quid = $attributes["id"];
  1569. $format = $attributes["format"];
  1570. $where = $attributes["where"];
  1571. $tableheadings = (isset($attributes["tableheadings"]));
  1572. if ($quid != "") {
  1573. $qQ = dbrecordset("SELECT * FROM ax_query_resource WHERE quid=$quid");
  1574. if ($qQ->hasdata) {
  1575. // Datasource content..
  1576. if ($qQ->field("q_query") != "") {
  1577. $datasrc = unserialize($qQ->field("q_query"));
  1578. // Apply any block-level where clause..
  1579. if ($where != "") {
  1580. if ($datasrc->where->total > 0) {
  1581. if (strtolower(substr($where, 0, 3)) != "and") {
  1582. $where = "and $where";
  1583. }
  1584. }
  1585. $datasrc->where($where);
  1586. }
  1587. $raw_content = "";
  1588. // Handle table headings if required..
  1589. if ($format == "table" && $tableheadings) {
  1590. $fieldnames = explode(",", $datasrc->fields->listed());
  1591. $headings = array();
  1592. foreach ($fieldnames as $fieldname) {
  1593. if (strstr($fieldname, ".")) {
  1594. $bits = explode(".", $fieldname);
  1595. $fieldname = $bits[1];
  1596. }
  1597. $headings[] = ucfirst(str_replace("_", " ", $fieldname));
  1598. }
  1599. $raw_content .= implode("^", $headings) . "\n";
  1600. }
  1601. // Get datasource data..
  1602. $datasrc->execute();
  1603. if ($datasrc->hasdata) {
  1604. do {
  1605. $data = array();
  1606. for ($i=0; $i < $datasrc->fields->total; $i++) {
  1607. $data[] = $datasrc->current_row[$i];
  1608. }
  1609. switch ($format) {
  1610. case "list":
  1611. case "ordered":
  1612. case "bullets":
  1613. $raw_content .= implode(" ", $data) . "\n";
  1614. break;
  1615. case "table":
  1616. $raw_content .= implode("|", $data) . "\n";
  1617. break;
  1618. default:
  1619. $raw_content .= implode(" ", $data);
  1620. } // switch
  1621. } while ($datasrc->get_next());
  1622. $new_content = $this->format_content(
  1623. $raw_content,
  1624. $format,
  1625. $this->content_css()
  1626. );
  1627. }
  1628. }
  1629. // Script-generated content..
  1630. elseif ($qQ->field("q_script") != "") {
  1631. debugbr("execute script here.", DBG_DEBUG);
  1632. }
  1633. }
  1634. }
  1635. // case data
  1636. break;
  1637. // IMAGE
  1638. case "image":
  1639. $catid = $attributes["id"];
  1640. $align = $attributes["align"];
  1641. $pad = $attributes["pad"];
  1642. $tooltip = $attributes["title"];
  1643. $width = $attributes["width"];
  1644. $height = $attributes["height"];
  1645. $border = $attributes["border"];
  1646. $bdcolor = $attributes["bordercolor"];
  1647. if ($catid != "") {
  1648. $qQ = dbrecordset("SELECT * FROM ax_catalog WHERE cat_id=$catid");
  1649. if ($qQ->hasdata) {
  1650. $src = $qQ->field("filepath");
  1651. if ($width == 0 || $width == "") $width = $qQ->field("width");
  1652. if ($width == 0 || $width == "") $width = false;
  1653. if ($height == 0 || $height == "") $height = $qQ->field("height");
  1654. if ($height == 0 || $height == "") $height = false;
  1655. $img=new img($src, $catid, $tooltip, $width, $height);
  1656. if ($border != "") {
  1657. $img->setborder($border);
  1658. $img->setstyle("border-style:solid;border-width:" . $border . "px;");
  1659. if ($bdcolor != "") $img->setstyle("border-color:$bdcolor;");
  1660. }
  1661. if ($align != "") $img->setalign($align);
  1662. if ($pad != "") {
  1663. $img->sethspace($pad);
  1664. $img->setvspace($pad);
  1665. }
  1666. $new_content = $img->render();
  1667. }
  1668. }
  1669. break;
  1670. // MEDIA or DOCUMENT
  1671. case "media":
  1672. case "document":
  1673. $new_content = "";
  1674. $catid = $attributes["id"];
  1675. $display = $attributes["display"];
  1676. $width = $attributes["width"];
  1677. $height = $attributes["height"];
  1678. if ($mediatype == "media") {
  1679. $autostart = ($attributes["autostart"] == "yes");
  1680. $loop = ($attributes["loop"] == "yes");
  1681. $showcontrols = ($attributes["showcontrols"] == "yes");
  1682. }
  1683. if ($width == 0 || $width == "") $width = 200;
  1684. if ($height == 0 || $height == "") $height = 200;
  1685. $tooltip = $attributes["title"];
  1686. if ($catid != "") {
  1687. $qQ = dbrecordset("SELECT * FROM ax_catalog WHERE cat_id=$catid");
  1688. if ($qQ->hasdata) {
  1689. $src = $qQ->field("filepath");
  1690. $category = $qQ->field("mime_category");
  1691. switch ($category) {
  1692. case "movie":
  1693. $media = new MediaObject($src, $width, $height, $autostart, $loop, $showcontrols);
  1694. switch ($display) {
  1695. case "icon": $media->AsIcon($tooltip); break;
  1696. case "link": $media->AsLink($tooltip); break;
  1697. }
  1698. break;
  1699. case "audio":
  1700. $media = new MediaObject($src, $width, $height, $autostart, $loop, $showcontrols);
  1701. switch ($display) {
  1702. case "icon": $media->AsIcon($tooltip); break;
  1703. case "link": $media->AsLink($tooltip); break;
  1704. }
  1705. break;
  1706. case "flash":
  1707. $media = new FlashObject($src, $width, $height, $autostart, $loop);
  1708. switch ($display) {
  1709. case "icon": $media->AsIcon($tooltip); break;
  1710. case "link": $media->AsLink($tooltip); break;
  1711. }
  1712. break;
  1713. case "document":
  1714. $media = new DocumentObject($src, $width, $height);
  1715. switch ($display) {
  1716. case "icon": $media->AsIcon($tooltip); break;
  1717. case "link": $media->AsLink($tooltip, "_new"); break;
  1718. }
  1719. break;
  1720. } // switch
  1721. if (is_object($media)) {
  1722. $new_content = $media->render();
  1723. }
  1724. }
  1725. }
  1726. break;
  1727. }// switch
  1728. } // got attributes
  1729. // Replace data tag with new content..
  1730. $new_content = str_replace("<img ", "<AXYL_IMAGE ", $new_content);
  1731. $content = str_replace($datatag, $new_content, $content);
  1732. }
  1733. } // while
  1734.  
  1735. // Return the processed content..
  1736. $content = str_replace("<AXYL_IMAGE ", "<img ", $content);
  1737. return $content;
  1738.  
  1739. } // expanded_content
  1740. // ....................................................................
  1741. /**
  1742. * Render the blocklet.
  1743. * @return string The HTML
  1744. */
  1745. function html() {
  1746. debug_trace($this);
  1747.  
  1748. $s = "";
  1749.  
  1750. // Main Blocklet Table
  1751. $btable = new table("BKT_$this->blockletid");
  1752.  
  1753. // Set table width if specified..
  1754. if ($this->width != "") {
  1755. $btable->setwidth($this->width . "%");
  1756. }
  1757.  
  1758. if ($RESPONSE->browser != BROWSER_NETSCAPE) {
  1759. $btable->setalign($this->justify);
  1760. }
  1761.  
  1762. // TOP RULER
  1763. if ($this->ruler == "top") {
  1764. $btable->tr();
  1765. $rul = new hr("$this->ruler_width%", $this->ruler_size, $this->ruler_colour);
  1766. $btable->td( $rul->render() );
  1767. $btable->td_alignment($this->justify);
  1768. }
  1769.  
  1770. // HEADING
  1771. if ($this->heading != "") {
  1772. $HTAG = "h$this->heading_level";
  1773. $btable->tr();
  1774. $btable->td("<$HTAG>" . $this->heading . "</$HTAG>");
  1775. $btable->td_alignment($this->justify);
  1776. if ($this->heading_colour != "") {
  1777. $btable->td_contentcss("color:$this->heading_colour");
  1778. }
  1779. }
  1780.  
  1781. // CONTENT
  1782. // First, expand any special tags..
  1783. $content = $this->expanded_content();
  1784.  
  1785. // Now, render the content..
  1786. if ($content != "") {
  1787. $btable->tr();
  1788. // Format the content..
  1789. $scell = $this->format_content(
  1790. $content,
  1791. $this->type,
  1792. $this->content_css()
  1793. );
  1794. // Add the blocklet content to the table..
  1795. $btable->td($scell);
  1796. $btable->td_alignment($this->justify);
  1797. } // if got content
  1798.  
  1799. // BOTTOM RULER
  1800. if ($this->ruler == "bottom") {
  1801. $btable->tr();
  1802. $rul = new hr("$this->ruler_width%", $this->ruler_size, $this->ruler_colour);
  1803. $btable->td( $rul->render() );
  1804. $btable->td_alignment($this->justify);
  1805. }
  1806.  
  1807. // END TABLE DIV
  1808. $s .= $btable->render();
  1809.  
  1810. debug_trace();
  1811. // Return the HTML..
  1812. return $s;
  1813. } // html
  1814.  
  1815.  
  1816.  
  1817. } // blocklet class
  1818. // ----------------------------------------------------------------------
  1819.  
  1820. /** Utility function to extract content attributes from string.
  1821. * Incoming Format is:
  1822. * <tagname attrname="attrvalue" attrname="attrvalue" ... >
  1823. * Returns an associative array:
  1824. * An element 'tagname' will contain the tag name:
  1825. * returnedarray["tagname"] = tagname
  1826. * Other elements one for each attribute:
  1827. * returnedarray["attrname"] = attrvalue
  1828. * @access private
  1829. */
  1830. function extractAttributes($str){
  1831. $attrs = array();
  1832. $matches = "";
  1833. if (preg_match("/<(.*?) (.*?)>/i", $str, $matches) ) {
  1834. $attrs["tagname"] = $matches[1];
  1835. $attributes = trim($matches[2]);
  1836. if (preg_match_all("/(.*?)=\"(.*?)\"/i", $attributes, $matches)) {
  1837. $total = count($matches[0]);
  1838. for ($tagno = 0; $tagno < $total; $tagno++) {
  1839. if (trim($matches[1][$tagno]) != "") {
  1840. $attrname = trim(strtolower($matches[1][$tagno]));
  1841. $attrval = trim($matches[2][$tagno]);
  1842. $attrs[$attrname] = $attrval;
  1843. }
  1844. }
  1845. }
  1846. }
  1847. return $attrs;
  1848. } // extractAttributes
  1849. // ----------------------------------------------------------------------
  1850.  
  1851. ?>

Documentation generated by phpDocumentor 1.3.0RC3