diff options
29 files changed, 1949 insertions, 0 deletions
diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..3bd1bde --- /dev/null +++ b/.htaccess @@ -0,0 +1,9 @@ +<IfModule mod_rewrite.c> + RewriteEngine on + RewriteBase /pigeonholes/ + RewriteCond %{SCRIPT_FILENAME} -f [OR] + RewriteCond %{SCRIPT_FILENAME}/index.php -f + RewriteRule ^(.*)$ - [L] + + RewriteRule ^(.*)$ index.php?content_id=$1 [L] +</IfModule> diff --git a/Pigeonholes.php b/Pigeonholes.php new file mode 100644 index 0000000..3d8febf --- /dev/null +++ b/Pigeonholes.php @@ -0,0 +1,747 @@ +<?php +/** + * @version $Header: /cvsroot/bitweaver/_bit_pigeonholes/Pigeonholes.php,v 1.1 2005/08/21 16:22:44 squareing Exp $ + * + * +----------------------------------------------------------------------+ + * | Copyright ( c ) 2004, bitweaver.org + * +----------------------------------------------------------------------+ + * | All Rights Reserved. See copyright.txt for details and a complete list of authors. + * | Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details + * | + * | For comments, please use phpdocu.sourceforge.net documentation standards!!! + * | -> see http://phpdocu.sourceforge.net/ + * +----------------------------------------------------------------------+ + * | Authors: xing <xing@synapse.plus.com> + * +----------------------------------------------------------------------+ + * + * Pigeonholes class + * + * @author xing <xing@synapse.plus.com> + * @version $Revision: 1.1 $ + * @package pigeonholes + */ + +/** + * required setup + */ +require_once( LIBERTY_PKG_PATH.'LibertyAttachable.php' ); +require_once( LIBERTY_PKG_PATH.'LibertyStructure.php' ); + +/** + * Pigeonholes + * + * @package pigeonholes + */ +class Pigeonholes extends LibertyAttachable { + /** + * initiate class + * @param $pContentId content id of the pigeonhole - use either one of the ids. + * @param $pStructureId structure id of the pigeonhole - use either one of the ids. + * @param $pAutoLoad boolean - if set to FALSE, no pigeonhole data is loaded + * @param $pExtras boolean - if set to TRUE, pigeonhole content is added as well - 1 additional db access + * @return none + * @access public + **/ + function Pigeonholes( $pStructureId=NULL, $pContentId=NULL, $pAutoLoad=TRUE, $pExtras=FALSE ) { + LibertyAttachable::LibertyAttachable(); + $this->registerContentType( PIGEONHOLES_CONTENT_TYPE_GUID, array( + 'content_type_guid' => PIGEONHOLES_CONTENT_TYPE_GUID, + 'content_description' => 'Pigeonhole', + 'handler_class' => 'Pigeonholes', + 'handler_package' => 'pigeonholes', + 'handler_file' => 'Pigeonholes.php', + 'maintainer_url' => 'http://www.bitweaver.org' + ) ); + $this->mContentId = $pContentId; + $this->mStructureId = $pStructureId; + $this->mContentTypeGuid = PIGEONHOLES_CONTENT_TYPE_GUID; + if( $pAutoLoad ) { + $this->load( $pExtras ); + } + } + + /** + * load the pigeonhole + * @param $pExtras boolean - if set to true, pigeonhole content is added as well + * @return bool TRUE on success, FALSE if it's not valid + * @access public + **/ + function load( $pExtras=FALSE ) { + if( $this->verifyId( $this->mContentId ) || $this->verifyId( $this->mStructureId ) ) { + global $gBitSystem; + $lookupColumn = ( !empty( $this->mContentId ) ? 'tc.`content_id`' : 'ts.`structure_id`' ); + $lookupId = ( !empty( $this->mContentId ) ? $this->mContentId : $this->mStructureId ); + $query = "SELECT bp.*, ts.`root_structure_id`, ts.`parent_id`, tc.`title`, tc.`data`, tc.`content_type_guid`, + uue.`login` AS modifier_user, uue.`real_name` AS modifier_real_name, + uuc.`login` AS creator_user, uuc.`real_name` AS creator_real_name + FROM `".BIT_DB_PREFIX."bit_pigeonholes` bp + INNER JOIN `".BIT_DB_PREFIX."tiki_content` tc ON ( tc.`content_id` = bp.`content_id` ) + LEFT JOIN `".BIT_DB_PREFIX."tiki_structures` ts ON ( ts.`structure_id` = bp.`structure_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uue ON ( uue.`user_id` = tc.`modifier_user_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uuc ON ( uuc.`user_id` = tc.`user_id` ) + WHERE $lookupColumn=?"; + $result = $this->mDb->query( $query, array( $lookupId ) ); + + if ( $result && $result->numRows() ) { + $this->mInfo = $result->fields; + $this->mContentId = $result->fields['content_id']; + $this->mStructureId = $result->fields['structure_id']; + $this->mInfo['creator'] = ( isset( $result->fields['creator_real_name'] ) ? $result->fields['creator_real_name'] : $result->fields['creator_user'] ); + $this->mInfo['editor'] = ( isset( $result->fields['modifier_real_name'] ) ? $result->fields['modifier_real_name'] : $result->fields['modifier_user'] ); + $this->mInfo['display_link'] = $this->getDisplayLink(); + } + + // if the content for the pigeonhole is requested, get it + if( $pExtras ) { + $this->mInfo['path'] = $this->getPigeonholePath(); + $this->mInfo['display_path'] = $this->getDisplayPath( $this->mInfo['path'] ); + $this->mInfo['members'] = $this->getPigeonholeMembers(); + $this->mInfo['members_count'] = count( $this->mInfo['members'] ); + } + } + return( count( $this->mInfo ) ); + } + + /** + * get all content inserted in a given pigeonhole. if no id is given, it gets all content for all pigeonholes + * @param $pContentId content id of the pigeonhole + * @return array of pigeonhole members with according title and content type guid + * @access public + **/ + function getPigeonholeMembers( $pContentId=NULL ) { + global $gBitUser, $gLibertySystem, $gBitSystem; + $ret = FALSE; + if( !empty( $this->mContentId ) || !empty( $pContentId ) ) { + if( $gBitSystem->isFeatureActive( 'custom_member_sorting' ) ) { + $order = "ORDER BY bpm.`pos` ASC"; + } else { + $order = "ORDER BY tc.`content_type_guid`, tc.`title` ASC"; + } + + $bindVars[] = $this->verifyId( $pContentId ) ? $pContentId : $this->mContentId; + $ret = array(); + $query = "SELECT bpm.*, tc.`content_id`, tc.`user_id`, tc.`title`, tc.`content_type_guid`, uu.`login`, uu.`real_name` + FROM `".BIT_DB_PREFIX."bit_pigeonhole_members` bpm + RIGHT JOIN `".BIT_DB_PREFIX."bit_pigeonholes` bp ON ( bp.`content_id` = bpm.`parent_id` ) + INNER JOIN `".BIT_DB_PREFIX."tiki_content` tc ON ( tc.`content_id` = bpm.`content_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uu ON ( uu.`user_id` = tc.`user_id` ) + WHERE bp.`content_id`=? + $order"; + $result = $this->mDb->query( $query, $bindVars ); + $contentTypes = $gLibertySystem->mContentTypes; + while( !$result->EOF ) { + $i = $result->fields['content_id']; + $ret[$i] = $result->fields; + if( !empty( $contentTypes[$ret[$i]['content_type_guid']] ) ) { + $type = &$contentTypes[$ret[$i]['content_type_guid']]; + if( empty( $type['content_object'] ) ) { + // create *one* object for each object *type* to call virtual methods. + include_once( $gBitSystem->mPackages[$type['handler_package']]['path'].$type['handler_file'] ); + $type['content_object'] = new $type['handler_class'](); + } + $ret[$i]['display_link'] = $type['content_object']->getDisplayLink( $ret[$i]['title'], $ret[$i] ); + $ret[$i]['title'] = $type['content_object']->getTitle( $ret[$i] ); + } + $result->MoveNext(); + } + } else { + $this->mErrors['get_members'] = tra( 'No valid pigeonhole id given to collect members from.' ); + } + return( !empty( $ret ) ? $ret : NULL ); + } + + /** + * get all items that are not part of a pigeonhole yet + * @param $pContentType content type guid of items to be collected. if empty, all content is collected + * @param $pIncludeMembers if set to TRUE (boolean), it will return members as well, where the pigeonholes they are assigned to, are in the sub array 'assigned' + * @return array of content not in any pigeonhole yet + * @access public + **/ + function getNonPigeonholeMembers( $pListHash=NULL, $pContentType=NULL, $pIncludeMembers=FALSE ) { + global $gBitUser, $gLibertySystem, $gBitSystem; + $where = ''; + $bindVars = array(); + + if( !$pIncludeMembers ) { + $where .= "WHERE tc.`content_id` NOT IN ( SELECT DISTINCT `content_id` FROM `".BIT_DB_PREFIX."bit_pigeonhole_members` )"; + } + + if( !empty( $pListHash['find'] ) && is_string( $pListHash['find'] ) ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= " UPPER( tc.`title` ) LIKE ?"; + $bindVars[] = ( '%'.strtoupper( $pListHash['find'] ).'%'); + } + + if( $pContentType ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= " tc.`content_type_guid`=?"; + $bindVars[] = $pContentType; + } + + if( !empty( $pListHash['sort_mode'] ) ) { + $where .= " ORDER BY ".$this->mDb->convert_sortmode( $pListHash['sort_mode'] )." "; + } else { + $where .= " ORDER BY tc.`content_type_guid`, tc.`title` ASC"; + } + + $query = "SELECT bpm.`parent_id`, tc.`content_id`, tc.`user_id`, tc.`title`, tc.`content_type_guid`, uu.`login`, uu.`real_name` + FROM `".BIT_DB_PREFIX."tiki_content` tc + LEFT JOIN `".BIT_DB_PREFIX."bit_pigeonhole_members` bpm ON ( bpm.`content_id` = tc.`content_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uu ON ( uu.`user_id` = tc.`user_id` ) + $where"; + $result = $this->mDb->query( $query, $bindVars, empty( $pListHash['max_rows'] ) ? NULL : $pListHash['max_rows'] ); + + $contentTypes = $gLibertySystem->mContentTypes; + while( !$result->EOF ) { + $i = $result->fields['content_id']; + $ret[$i] = $result->fields; + if( !empty( $contentTypes[$ret[$i]['content_type_guid']] ) ) { + $type = &$contentTypes[$ret[$i]['content_type_guid']]; + if( empty( $type['content_object'] ) ) { + // create *one* object for each object *type* to call virtual methods. + include_once( $gBitSystem->mPackages[$type['handler_package']]['path'].$type['handler_file'] ); + $type['content_object'] = new $type['handler_class'](); + } + $ret[$i]['display_link'] = $type['content_object']->getDisplayLink( $ret[$i]['title'], $ret[$i] ); + $ret[$i]['title'] = $type['content_object']->getTitle( $ret[$i] ); + } + + // generate a map of what items are assigned to what pigeonholes + if( $pIncludeMembers && !empty( $result->fields['parent_id'] ) ) { + $map[$i][] = $result->fields['parent_id']; + } + + $result->MoveNext(); + } + + // complete the output + if( $pIncludeMembers && !empty( $ret ) ) { + foreach( $ret as $i => $r ) { + $ret[$i]['assigned'] = !empty( $map[$i] ) ? $map[$i] : NULL; + } + } + + return( !empty( $ret ) ? $ret : NULL ); + } + + /** + * get an array of paths for all pigeonholes. used for pages where data can be inserted into pigeonholes + * @param $pContentId content id of pigeonhole. + * @return path in form of an array on success, FALSE ( boolean ) if content is in no pigeonhole + * @access public + * @TODO sort the array somehow to make sure that the path is always incrementing and looks nice... + **/ + function getPigeonholesPathList( $pContentId=NULL ) { + $query = "SELECT bp.`content_id`, bp.`structure_id` + FROM `".BIT_DB_PREFIX."bit_pigeonholes` bp + ORDER BY bp.`content_id` ASC"; + $result = $this->mDb->query( $query ); + $pigeonholes = $result->getRows(); + foreach( $pigeonholes as $pigeonhole ) { + $ret[$pigeonhole['content_id']] = $this->getPigeonholePath( $pigeonhole['structure_id'] ); + } + + if( !empty( $pContentId ) && $assigned = $this->getPigeonholesFromContentId( $pContentId ) ) { + foreach( $assigned as $a ) { + $ret[$a['content_id']][0]['selected'] = TRUE; + } + } + + return( !empty( $ret ) ? $ret : FALSE ); + } + + /** + * get all pigeonholes where the contenent has been inserted + * @param $pContentId content id of item in question + * @return basic information about item requested + * @access public + **/ + function getPigeonholesFromContentId( $pContentId ) { + if( $this->verifyId( $pContentId ) ) { + $query = "SELECT bp.* + FROM `".BIT_DB_PREFIX."bit_pigeonhole_members` bpm + INNER JOIN `".BIT_DB_PREFIX."bit_pigeonholes` bp ON ( bp.`content_id` = bpm.`parent_id` ) + WHERE bpm.`content_id`=?"; + $result = $this->mDb->query( $query, array( $pContentId ) ); + $ret = $result->getRows(); + } + return( !empty( $ret ) ? $ret : FALSE ); + } + + /** + * get the path of a pigeonhole + * @param $pStructureId structure id of pigeonhole, if no id is given, it gets the id from $this->mStructureId + * @return path in form of an array + * @access public + **/ + function getPigeonholePath( $pStructureId=NULL ) { + if( !$this->verifyId( $pStructureId ) ) { + $pStructureId = $this->mStructureId; + } + + if( $this->verifyId( $pStructureId ) ) { + global $gStructure; + // create new object if needed + if( empty( $gStructure ) ) { + $gStructure = new LibertyStructure(); + } + // get the structure path + $ret = $gStructure->getPath( $pStructureId ); + } + return( !empty( $ret ) ? $ret : FALSE ); + } + + /** + * Converts a structure path into valid html links + * @param $pPath path given by getPigenholePath() + * @return the link to display the page. + */ + function getDisplayPath( $pPath ) { + $ret = ''; + if( !empty( $pPath ) && is_array( $pPath ) ) { + foreach( $pPath as $node ) { + $ret .= ( !empty( $node['parent_id'] ) ? ' » ' : '' ).'<a href="'.PIGEONHOLES_PKG_URL.'view.php?structure_id='.$node['structure_id'].'">'.$node['title'].'</a>'; + } + } + return $ret; + } + + /** + * get list of all pigeonholes + * @param $pListHash contains array of items used to limit search results + * @param $pListHash[sort_mode] column and orientation by which search results are sorted + * @param $pListHash[find] search for a pigeonhole title - case insensitive + * @param $pListHash[max_rows] maximum number of rows to return + * @param $pListHash[offset] number of results data is offset by + * @return array of pigeonholes in 'data' and count of pigeonholes in 'cant' + * @access public + **/ + function getList( $pListHash=NULL, $pOnlyGetRoot=FALSE, $pExtras=FALSE ) { + $bindVars = array(); + $where = ''; + if( !empty( $pListHash['find'] ) ) { + $where .= " WHERE UPPER( tc.`title` ) LIKE ? "; + $bindVars[] = '%'.strtoupper( $pListHash['find'] ).'%'; + } + + if( !empty( $pListHash['root_structure_id'] ) && $this->verifyId( $pListHash['root_structure_id'] ) ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= " ts.`root_structure_id`=? "; + $bindVars[] = $pListHash['root_structure_id']; + } + + if( $pOnlyGetRoot ) { + $where .= empty( $where ) ? ' WHERE ' : ' AND '; + $where .= " ts.`structure_id`=ts.`root_structure_id` "; + } + + if( !empty( $pListHash['sort_mode'] ) ) { + $where .= " ORDER BY ".$this->mDb->convert_sortmode( $pListHash['sort_mode'] )." "; + } + + $query = "SELECT bp.`content_id`, + uue.`login` AS modifier_user, uue.`real_name` AS modifier_real_name, + uuc.`login` AS creator_user, uuc.`real_name` AS creator_real_name + FROM `".BIT_DB_PREFIX."bit_pigeonholes` bp + INNER JOIN `".BIT_DB_PREFIX."tiki_content` tc ON ( tc.`content_id` = bp.`content_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uue ON ( uue.`user_id` = tc.`modifier_user_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uuc ON ( uuc.`user_id` = tc.`user_id` ) + INNER JOIN `".BIT_DB_PREFIX."tiki_structures` ts ON ( ts.`structure_id` = bp.`structure_id` ) + $where"; + + if( isset( $pListHash['max_rows'] ) && is_numeric( $pListHash['max_rows'] ) && isset( $pListHash['offset'] ) && is_numeric( $pListHash['offset'] ) ) { + $result = $this->mDb->query( $query, $bindVars, $pListHash['max_rows'], $pListHash['offset'] ); + } else { + $result = $this->mDb->query( $query, $bindVars ); + } + + $pigeonIds = $result->getRows(); + $ret['data'] = array(); + foreach( $pigeonIds as $id ) { + $tmpPigeon = new Pigeonholes( NULL, $id['content_id'], TRUE, $pExtras ); + $ret['data'][] = $tmpPigeon->mInfo; + } + + $query = "SELECT COUNT( bp.`content_id` ) + FROM `".BIT_DB_PREFIX."bit_pigeonholes` bp + INNER JOIN `".BIT_DB_PREFIX."tiki_structures` ts ON ( ts.`structure_id` = bp.`structure_id` ) + WHERE ts.`structure_id`=ts.`root_structure_id`"; + $ret['cant'] = $this->mDb->getOne( $query ); + + return $ret; + } + + /** + * Store pigeonhole data + * @param $pParamHash contains all data to store the pigeonholes + * @param $pParamHash[title] title of the new pigeonhole + * @param $pParamHash[edit] description of the pigeonhole + * @param $pParamHash[members] array of content_ids that are associated with this pigeonhole + * @param $pParamHash[root_structure_id] if this is set, it will add the pigeonhole to this structure. if it's not set, a new structure / top level pigeonhole is created + * @param $pParamHash[parent_id] set the structure_id that will server as the parent in the structure + * @return bool TRUE on success, FALSE if store could not occur. If FALSE, $this->mErrors will have reason why + * @access public + **/ + function store( &$pParamHash ) { + if( $this->verify( $pParamHash ) && LibertyAttachable::store( $pParamHash ) ) { + $table = BIT_DB_PREFIX."bit_pigeonholes"; + $this->mDb->StartTrans(); + + // this really confusing, strange order way of saving items is due to strange behaviour of GenID + // probably has to do with not null default nextval('public.tiki_structures_structure_id_seq'::text) + if( $this->mContentId ) { + if( !empty( $pParamHash['pigeonhole_store'] ) ) { + $locId = array ( "name" => "content_id", "value" => $this->mContentId ); + $result = $this->mDb->associateUpdate( $table, $pParamHash['pigeonhole_store'], $locId ); + } + $pParamHash['structure_location_id'] = $this->mStructureId; + } else { + // update the pigeonhole_store and structure_store content_id with the one from LibertyAttachable::store() + $pParamHash['structure_store']['content_id'] = $pParamHash['content_id']; + $pParamHash['pigeonhole_store']['content_id'] = $pParamHash['content_id']; + + // we need to store the new structure node now + global $gStructure; + // create new object if needed + if( empty( $gStructure ) ) { + $gStructure = new LibertyStructure(); + } + $pParamHash['structure_location_id'] = $gStructure->storeNode( $pParamHash['structure_store'] ); + + // get the corrent structure_id + // structure_id has to be done like this since it's screwed up in the schema + $pParamHash['pigeonhole_store']['structure_id'] = $this->mDb->getOne( "SELECT MAX( `structure_id` ) FROM `".BIT_DB_PREFIX."tiki_structures`" ); + $this->mContentId = $pParamHash['pigeonhole_store']['content_id']; + $result = $this->mDb->associateInsert( $table, $pParamHash['pigeonhole_store'] ); + } + + // store content items + if( !empty( $pParamHash['pigeonhole_members_store'] ) ) { + // remove items first + $this->expungePigeonholeMember( $this->mContentId ); + if( !$this->insertPigeonholeMember( $pParamHash['pigeonhole_members_store'] ) ) { + $this->mErrors['store'] = 'The content could not be inserted into the respective categories.'; + } + } + + $this->mDb->CompleteTrans(); + $this->load(); + } + return( count( $this->mErrors ) == 0 ); + } + + /** + * verify, clean up and prepare data to be stored + * @param $pParamHash all information that is being stored. will update $pParamHash by reference with fixed array of itmes + * @return bool TRUE on success, FALSE if store could not occur. If FALSE, $this->mErrors will have reason why + * @access private + **/ + function verify( &$pParamHash ) { + // make sure we're all loaded up if everything is valid + if( $this->isValid() && empty( $this->mInfo ) ) { + $this->load( TRUE ); + } + + // It is possible a derived class set this to something different + if( empty( $pParamHash['content_type_guid'] ) ) { + $pParamHash['content_type_guid'] = $this->mContentTypeGuid; + } + + if( !empty( $this->mContentId ) ) { + $pParamHash['content_id'] = $this->mContentId; + } + + // content store + // check for name issues, first truncate length if too long + if( !empty( $pParamHash['title'] ) ) { + if( empty( $this->mContentId ) ) { + if( empty( $pParamHash['title'] ) ) { + $this->mErrors['title'] = 'You must enter a name for this category.'; + } else { + $pParamHash['content_store']['title'] = substr( $pParamHash['title'], 0, 160 ); + } + } else { + $pParamHash['content_store']['title'] = ( isset( $pParamHash['title'] ) ) ? substr( $pParamHash['title'], 0, 160 ) : $this->mPigeonholeName; + } + } elseif( empty( $pParamHash['title'] ) ) { + // no name specified + $this->mErrors['title'] = 'You must specify a name'; + } + + // sort out the description + if( $this->isValid() && !empty( $this->mInfo['data'] ) && empty( $pParamHash['edit'] ) ) { + $pParamHash['edit'] = ''; + } elseif( empty( $pParamHash['edit'] ) ) { + unset( $pParamHash['edit'] ); + } else { + $pParamHash['edit'] = substr( $pParamHash['edit'], 0, 250 ); + } + + // pigeonhole member store + // work out what to do with the content of the pigeonhole + if( $this->isValid() && !empty( $this->mInfo['members'] ) && empty( $pParamHash['members'] ) ) { + $pParamHash['pigeonhole_members_store']['members'] = ''; + } elseif( empty( $pParamHash['members'] ) ) { + unset( $pParamHash['members'] ); + } else { + $i = 1; + $pos = 1; + + // if this is not the first save, we need to get positional data from members and insert them + if( !empty( $this->mContentId ) ) { + $members = $this->getPigeonholeMembers( $this->mContentId ); + $pos = count( $members ) + 1; + } + + foreach( $pParamHash['members'] as $c_id ) { + if( !empty( $members[$c_id]['pos'] ) ) { + $pParamHash['pigeonhole_members_store'][$i]['pos'] = $members[$c_id]['pos']; + } else { + $pParamHash['pigeonhole_members_store'][$i]['pos'] = $pos++; + } + $pParamHash['pigeonhole_members_store'][$i]['content_id'] = $c_id; + $i++; + } + } + + // structure store + if( !empty( $pParamHash['root_structure_id'] ) && $this->verifyId( $pParamHash['root_structure_id'] ) ) { + $pParamHash['structure_store']['root_structure_id'] = $pParamHash['root_structure_id']; + } else { + $pParamHash['structure_store']['root_structure_id'] = NULL; + } + + if( !empty( $pParamHash['parent_id'] ) && $this->verifyId( $pParamHash['parent_id'] ) ) { + $pParamHash['structure_store']['parent_id'] = $pParamHash['parent_id']; + } else { + $pParamHash['structure_store']['parent_id'] = NULL; + } + + return( count( $this->mErrors ) == 0 ); + } + + /** + * Move content member either up or down when using custom sorting + * @param $pParentId pigeonhole id the member belongs to + * @param $pMemberId content id of the pigeonhole member + * @param $pOrientation requires either north or south as value + * @return bool TRUE on success, FALSE if store could not occur. If FALSE, $this->mErrors will have reason why + * @access public + **/ + function moveMember( $pParentId, $pMemberId, $pOrientation ) { + if( $this->isValid() && !empty( $pParentId ) && is_numeric( $pParentId ) && !empty( $pMemberId ) && is_numeric( $pMemberId ) ) { + if( !empty( $pOrientation ) && $pOrientation == 'north' ) { + $query = "SELECT `parent_id`, `content_id`, `pos` FROM `".BIT_DB_PREFIX."bit_pigeonhole_members` WHERE `pos`<? AND `parent_id`=? ORDER BY `pos` DESC"; + } elseif ( !empty( $pOrientation ) && $pOrientation == 'south' ) { + $query = "SELECT `parent_id`, `content_id`, `pos` FROM `".BIT_DB_PREFIX."bit_pigeonhole_members` WHERE `pos`>? AND `parent_id`=? ORDER BY `pos` ASC"; + } else { + $this->mErrors['orientation'] = tra( 'The member could not be moved since the orientation is not known.' ); + } + + // execute sql if everything is in order so far + if( !empty( $query ) ) { + $this->mDb->StartTrans(); + $result = $this->mDb->query( $query, array( $this->mInfo['members'][$pMemberId]['pos'], $pParentId ) ); + $res = $result->fetchRow(); + if( $res ) { + //Swap positional values + $query = "UPDATE `".BIT_DB_PREFIX."bit_pigeonhole_members` SET `pos`=? WHERE `parent_id`=? AND `content_id`=?"; + $this->mDb->query( $query, array( $res['pos'], $pParentId, $pMemberId ) ); + $this->mDb->query( $query, array( $this->mInfo['members'][$pMemberId]['pos'], $res['parent_id'], $res['content_id'] ) ); + } + $this->mDb->CompleteTrans(); + } + } else { + $this->mErrors['move_member'] = tra( 'The category member could not be moved up, due to faulty data.' ); + } + return( count( $this->mErrors ) == 0 ); + } + + /** + * Store pigeonhole member + * @param $pParamHash an array of conent to be stored. + * @param $pParamHash[parent_id] id of pigeonhole it belongs to, default is $this->mContentId + * @param $pParamHash[content_id] content_id of the item to be stored + * @return bool TRUE on success, FALSE if store could not occur. If FALSE, $this->mErrors will have reason why + * @access public + **/ + function insertPigeonholeMember( &$pParamHash ) { + if( $this->verifyPigeonholeMember( $pParamHash ) ) { + foreach( $pParamHash['member_store'] as $item ) { + $result = $this->mDb->associateInsert( BIT_DB_PREFIX."bit_pigeonhole_members", $item ); + } + } else { + vd( $this->mErrors ); + } + return( count( $this->mErrors ) == 0 ); + } + + /** + * verify, clean up and prepare data to be stored + * @param $pParamHash all information that is being stored. will update $pParamHash by reference with fixed array of itmes + * @return bool TRUE on success, FALSE if store could not occur. If FALSE, $this->mErrors will have reason why + * @access private + **/ + function verifyPigeonholeMember( &$pParamHash ) { + $this->mDb->StartTrans(); + foreach( $pParamHash as $key => $item ) { + if( isset( $item['parent_id'] ) && $this->verifyId( $item['parent_id'] ) ) { + $tmp['member_store'][$key]['parent_id'] = $item['parent_id']; + } elseif( !empty( $this->mContentId ) ) { + $tmp['member_store'][$key]['parent_id'] = $this->mContentId; + $pParamHash[$key]['parent_id'] = $this->mContentId; + } else { + $this->mErrors['store_members'] = tra( 'The content could not be inserted because the parent_id was missing.' ); + } + + if( isset( $item['content_id'] ) && $this->verifyId( $item['content_id'] ) ) { + $tmp['member_store'][$key]['content_id'] = $item['content_id']; + } else { + $this->mErrors['store_members'] = 'The content id is not valid.'; + } + + // if no positional info is given, we just append the items. + if( isset( $item['pos'] ) && is_numeric( $item['content_id'] ) ) { + $tmp['member_store'][$key]['pos'] = $item['pos']; + } elseif( !empty( $tmp['member_store'][$key-1]['pos'] ) ) { + $tmp['member_store'][$key]['pos'] = $tmp['member_store'][$key-1]['pos'] + 1; + } else { + $query = "SELECT COUNT(*) FROM `".BIT_DB_PREFIX."bit_pigeonhole_members` WHERE `parent_id`=?"; + $tmp['member_store'][$key]['pos'] = $this->mDb->getOne( $query, array( $tmp['member_store'][$key]['parent_id'] ) ) + 1; + } + } + + $this->mDb->CompleteTrans(); + $pParamHash = $tmp; + return( count( $this->mErrors ) == 0 ); + } + + /** + * Expunge pigeonhole member + * @param $pMemberId content_id of content to be deleted + * Note if only one of the 2 ids is given, all items with that id will be removed. if both are given, only that one particular entry is removed + * @return bool TRUE on success, FALSE if store could not occur. If FALSE, $this->mErrors will have reason why + * @access public + **/ + function expungePigeonholeMember( $pParentId=NULL, $pMemberId=NULL ) { + if( !empty( $pParentId ) && $this->verifyId( $pParentId ) || !empty( $pMemberId ) && $this->verifyId( $pMemberId ) ) { + $where = ''; + if( $this->verifyId( $pParentId ) ) { + $where .= "WHERE `parent_id`=?"; + $bindVars[] = $pParentId; + } + + if( $this->verifyId( $pMemberId ) ) { + $where .= ( empty( $where ) ? "WHERE" : "AND" )." `content_id`=?"; + $bindVars[] = $pMemberId; + } + + $this->mDb->StartTrans(); + // depending on what data we've been given, we need to shift several items up to keep pos continuous + if( !empty( $pMemberId ) ) { + $query = "SELECT * FROM `".BIT_DB_PREFIX."bit_pigeonhole_members` $where"; + $result = $this->mDb->query( $query, $bindVars ); + $members = $result->getRows(); + foreach( $members as $member ) { + $query = "UPDATE `".BIT_DB_PREFIX."bit_pigeonhole_members` SET `pos`=`pos`-1 WHERE `pos`>? AND `parent_id`=?"; + $this->mDb->query( $query, array( $member['pos'], $member['parent_id'] ) ); + } + } + + // now we're ready to remove the actual members + $query = "DELETE FROM `".BIT_DB_PREFIX."bit_pigeonhole_members` $where"; + $result = $this->mDb->query( $query, $bindVars ); + $this->mDb->CompleteTrans(); + } else { + $this->mErrors['members_store'] = 'The category member(s) could not be removed.'; + } + return( count( $this->mErrors ) == 0 ); + } + + /** + * Expunge currently loaded pigeonhole + * @return bool TRUE on success, FALSE if store could not occur. + * @access public + **/ + function expunge() { + $ret = FALSE; + if( $this->isValid() ) { + $this->mDb->StartTrans(); + // get all items that are part of the sub tree + require_once( LIBERTY_PKG_PATH.'LibertyStructure.php' ); + $struct = new LibertyStructure(); + + $tree = $struct->getSubTree( $this->mStructureId ); + foreach( $tree as $node ) { + $structureIds[] = $node['structure_id']; + } + + $structureIds = array_unique( $structureIds ); + foreach( $structureIds as $structureId ) { + $contentIds[] = $this->mDb->getOne( "SELECT `content_id` FROM `".BIT_DB_PREFIX."tiki_structures` WHERE `structure_id`=?", array( $structureId ) ); + } + + foreach( $contentIds as $contentId ) { + // now we have the content ids - let the nuking begin + $query = "DELETE FROM `".BIT_DB_PREFIX."bit_pigeonholes` WHERE `content_id` = ?"; + $result = $this->mDb->query( $query, array( $contentId ) ); + $query = "DELETE FROM `".BIT_DB_PREFIX."bit_pigeonhole_members` WHERE `parent_id` = ?"; + $result = $this->mDb->query( $query, array( $contentId ) ); + + // remove all entries from content tables + $this->mContentId = $contentId; + if( LibertyAttachable::expunge() ) { + $ret = TRUE; + $this->mDb->CompleteTrans(); + } else { + $this->mDb->RollbackTrans(); + } + } + + // finally nuke the structure in tiki_structures + $struct->s_remove_page( $this->mStructureId, FALSE ); + } + return $ret; + } + + /** + * Generates the URL to this pigeonhole + * @param $pContentId is the pigeonhole id we want to see + * @return the link to display the page. + */ + function getDisplayUrl( $pContentId=NULL ) { + global $gBitSystem; + if( empty( $pContentId ) ) { + $pContentId = $this->mContentId; + } + + $rewrite_tag = $gBitSystem->isFeatureActive( 'feature_pretty_urls_extended' ) ? 'view/' : ''; + if( $gBitSystem->isFeatureActive( 'pretty_urls' ) || $gBitSystem->isFeatureActive( 'feature_pretty_urls_extended' ) ) { + $baseUrl = PIGEONHOLES_PKG_URL.$rewrite_tag.$pContentId; + } else { + $baseUrl = PIGEONHOLES_PKG_URL.'view.php?content_id='.$pContentId; + } + + return $baseUrl; + } + + /** + * Returns HTML link to display a pigeonhole + * @param $pPigeonholeTitle is the pigeonhole we want to see + * @return the link to display the page. + */ + function getDisplayLink( $pPigeonholeTitle=NULL ) { + global $gBitSystem; + if( empty( $pPigeonholeTitle ) && !empty( $this ) ) { + $pPigeonholeTitle = $this->mInfo['title']; + } + + $ret = $pPigeonholeTitle; + if( $gBitSystem->isPackageActive( 'pigeonholes' ) ) { + $ret = '<a href="'.$this->getDisplayUrl().'">'.$pPigeonholeTitle.'</a>'; + } + + return $ret; + } +} +?> diff --git a/admin/admin_pigeonholes_inc.php b/admin/admin_pigeonholes_inc.php new file mode 100644 index 0000000..616547f --- /dev/null +++ b/admin/admin_pigeonholes_inc.php @@ -0,0 +1,41 @@ +<?php +// $Header: /cvsroot/bitweaver/_bit_pigeonholes/admin/admin_pigeonholes_inc.php,v 1.1 2005/08/21 16:22:48 squareing Exp $ + +$pigeonholeSettings = array( + 'custom_member_sorting' => array( + 'label' => 'Custom Sorting', + 'note' => 'This will change the way category members are displayed. It allows you to sort the members manually.', + ), + 'display_pigeonhole_path' => array( + 'label' => 'Display Path', + 'note' => 'Display category paths above the page leading to the object.', + ), + 'display_pigeonhole_members' => array( + 'label' => 'Display Members', + 'note' => 'Show the other members of the same categories at the bottom of the page.', + ), + 'display_pigeonhole_description' => array( + 'label' => 'Display Description', + 'note' => 'When showing the category members, you can display the category description as well.', + ), +); +$gBitSmarty->assign( 'pigeonholeSettings', $pigeonholeSettings ); + +$memberLimit = array( + '9999' => 'Unlimited', + '10' => 10, + '20' => 20, + '30' => 30, + '50' => 50, + '100' => 100, +); +$gBitSmarty->assign( 'memberLimit', $memberLimit ); + +if( !empty( $_REQUEST['pigeonhole_settings'] ) ) { + foreach( array_keys( $pigeonholeSettings ) as $item ) { + simple_set_toggle( $item, PIGEONHOLES_PKG_NAME ); + } + + simple_set_value( 'limit_member_number', PIGEONHOLES_PKG_NAME ); +} +?> diff --git a/admin/schema_inc.php b/admin/schema_inc.php new file mode 100644 index 0000000..b041712 --- /dev/null +++ b/admin/schema_inc.php @@ -0,0 +1,54 @@ +<?php + +$tables = array( + 'bit_pigeonholes' => " + content_id I4 NOTNULL PRIMARY, + structure_id I4 NOTNULL PRIMARY + ", + 'bit_pigeonhole_members' => " + parent_id I4 NOTNULL PRIMARY, + content_id I4 NOTNULL PRIMARY, + pos I4 NOTNULL + " +); + +global $gBitInstaller; + +foreach( array_keys( $tables ) AS $tableName ) { + $gBitInstaller->registerSchemaTable( PIGEONHOLES_PKG_NAME, $tableName, $tables[$tableName] ); +} + +$gBitInstaller->registerPackageInfo( PIGEONHOLES_PKG_NAME, array( + 'description' => "A Categorisation system that makes it easy to keep an overview of your data. Has a simple, yet powerful interface for categorising multiple pages at once.", + 'license' => '<a href="http://www.gnu.org/licenses/licenses.html#LGPL">LGPL</a>', + 'version' => '0.1', + 'state' => 'experimental', + 'dependencies' => '', +) ); + +//// ### Indexes +//$indices = array ( +// 'bit_pigeonholes_content_idx' => array( 'table' => 'bit_pigeonholes', 'cols' => 'content_id', 'opts' => 'UNIQUE' ), +//); +//$gBitInstaller->registerSchemaIndexes( PIGEONHOLES_PKG_NAME, $indices ); + +// ### Sequences +$sequences = array ( + 'bit_pigeonholes_id_seq' => array( 'start' => 1 ) +); + +$gBitInstaller->registerSchemaSequences( PIGEONHOLES_PKG_NAME, $sequences ); + +// ### Default Preferences +$gBitInstaller->registerPreferences( PIGEONHOLES_PKG_NAME, array( + array( PIGEONHOLES_PKG_NAME, 'display_pigeonhole_members','y' ), +) ); + +// ### Default UserPermissions +$gBitInstaller->registerUserPermissions( PIGEONHOLES_PKG_NAME, array( + array( 'bit_p_view_pigeonholes', 'Can view pigeonholes', 'basic', PIGEONHOLES_PKG_NAME ), + array( 'bit_p_insert_pigeonhole_member', 'Can insert content into an existing pigeonhole', 'registered', PIGEONHOLES_PKG_NAME ), + array( 'bit_p_edit_pigeonholes', 'Can edit pigeonholes', 'editors', PIGEONHOLES_PKG_NAME ), +) ); + +?> diff --git a/assign_non_members.php b/assign_non_members.php new file mode 100644 index 0000000..18bc1ff --- /dev/null +++ b/assign_non_members.php @@ -0,0 +1,84 @@ +<?php +/** + * $Header: /cvsroot/bitweaver/_bit_pigeonholes/Attic/assign_non_members.php,v 1.1 2005/08/21 16:22:44 squareing Exp $ + * + * Copyright ( c ) 2004 bitweaver.org + * Copyright ( c ) 2003 tikwiki.org + * Copyright ( c ) 2002-2003, Luis Argerich, Garland Foster, Eduardo Polidor, et. al. + * All Rights Reserved. See copyright.txt for details and a complete list of authors. + * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details + * + * $Id: assign_non_members.php,v 1.1 2005/08/21 16:22:44 squareing Exp $ + * @package pigeonholes + * @subpackage functions + */ + +/** + * required setup + */ +require_once( '../bit_setup_inc.php' ); + +$gBitSystem->verifyPackage( 'pigeonholes' ); +$gBitSystem->verifyPermission( 'bit_p_insert_pigeonhole_member' ); + +include_once( PIGEONHOLES_PKG_PATH.'lookup_pigeonholes_inc.php' ); + +$feedback = ''; +$gBitSmarty->assign_by_ref( 'feedback', $feedback ); + +$contentTypes = array( '' => tra( 'All Content' ) ); +foreach( $gLibertySystem->mContentTypes as $cType ) { + $contentTypes[$cType['content_type_guid']] = $cType['content_description']; +} +$gBitSmarty->assign( 'contentTypes', $contentTypes ); +$gBitSmarty->assign( 'contentSelect', $contentSelect = !isset( $_REQUEST['content_type'] ) ? NULL : $_REQUEST['content_type'] ); + +$listHash = array( + 'find' => empty( $_REQUEST['find_objects'] ) ? NULL : $_REQUEST['find_objects'], + 'sort_mode' => empty( $_REQUEST['sort_mode'] ) ? NULL : $_REQUEST['sort_mode'], + 'max_rows' => ( !empty( $_REQUEST['max_rows'] ) && is_numeric( $_REQUEST['max_rows'] ) ) ? $_REQUEST['max_rows'] : 100, +); + +$nonMembers = $gPigeonholes->getNonPigeonholeMembers( $listHash, $contentSelect, ( !empty( $_REQUEST['include'] ) && $_REQUEST['include'] == 'members' ) ? $_REQUEST['include'] : FALSE ); + +if( !empty( $_REQUEST['insert_content'] ) && isset( $_REQUEST['pigeonhole'] ) ) { + // make an array that can be stored + foreach( $nonMembers as $item ) { + if( !empty( $_REQUEST['pigeonhole'][$item['content_id']] ) ) { + foreach( $_REQUEST['pigeonhole'][$item['content_id']] as $parent_id ) { + $memberHash[$parent_id][] = array( + 'parent_id' => $parent_id, + 'content_id' => $item['content_id'], + ); + } + } + + if( !empty( $_REQUEST['include'] ) && $_REQUEST['include'] == 'members' ) { + if( !empty( $item['content_id'] ) && !$gPigeonholes->expungePigeonholeMember( NULL, $item['content_id'] ) ) { + $feedback['error'] = 'The content could not be deleted before insertion.'; + } + } + } + + if( empty( $feedback['error'] ) ) { + foreach( $memberHash as $memberStore ) { + if( $gPigeonholes->insertPigeonholeMember( $memberStore ) ) { + $feedback['success'] = 'The content was successfully inserted into the respective categories.'; + } else { + $feedback['error'] = 'The content could not be inserted into the categories.'; + } + } + } + + // we need to reload the nonMembers, since settings have changed + $nonMembers = $gPigeonholes->getNonPigeonholeMembers( $listHash, $contentSelect, ( !empty( $_REQUEST['include'] ) && $_REQUEST['include'] == 'members' ) ? $_REQUEST['include'] : FALSE ); +} + +$pigeonList = $gPigeonholes->getList( NULL, FALSE, TRUE ); +$gBitSmarty->assign( 'pigeonList', $pigeonList['data'] ); +$gBitSmarty->assign( 'nonMembers', $nonMembers ); +$gBitSmarty->assign( 'contentCount', count( $nonMembers ) ); + +// Display the template +$gBitSystem->display( 'bitpackage:pigeonholes/assign_non_members.tpl', tra( 'Assign Content to Categories' ) ); +?> diff --git a/bit_setup_inc.php b/bit_setup_inc.php new file mode 100644 index 0000000..a8124f8 --- /dev/null +++ b/bit_setup_inc.php @@ -0,0 +1,31 @@ +<?php +/** + * @author xing <xing@synapse.plus.com> + * @version $Revision: 1.1 $ + * @package Pigeonholes + * @subpackage functions + */ +global $gBitSystem, $gBitUser; +$gBitSystem->registerPackage( 'pigeonholes', dirname( __FILE__).'/' ); + +define( 'PIGEONHOLES_CONTENT_TYPE_GUID', 'pigeonholes' ); + +if( $gBitSystem->isPackageActive( 'pigeonholes' ) ) { + $gLibertySystem->registerService( LIBERTY_SERVICE_CATEGORIZATION, PIGEONHOLES_PKG_NAME, array( + 'content_display_function' => 'display_pigeonholes', + 'content_preview_function' => 'pigeonholes_preview_content', + 'content_edit_function' => 'pigeonholes_input_content', + 'content_store_function' => 'pigeonholes_store_content', + 'content_edit_tpl' => 'bitpackage:pigeonholes/pigeonholes_input_inc.tpl', + 'content_view_tpl' => 'bitpackage:pigeonholes/display_members.tpl', + 'content_nav_tpl' => 'bitpackage:pigeonholes/display_paths.tpl', + ) ); + + // include service functions + require_once( PIGEONHOLES_PKG_PATH.'servicefunctions_inc.php' ); + + if( $gBitUser->hasPermission( 'bit_p_view_pigeonholes' ) ) { + $gBitSystem->registerAppMenu( 'pigeonholes', 'Categories', PIGEONHOLES_PKG_URL.'index.php', 'bitpackage:pigeonholes/menu_pigeonholes.tpl', 'Pigeonholes' ); + } +} +?> diff --git a/edit_pigeonholes.php b/edit_pigeonholes.php new file mode 100644 index 0000000..30fe015 --- /dev/null +++ b/edit_pigeonholes.php @@ -0,0 +1,146 @@ +<?php +/** + * $Header: /cvsroot/bitweaver/_bit_pigeonholes/edit_pigeonholes.php,v 1.1 2005/08/21 16:22:41 squareing Exp $ + * + * Copyright ( c ) 2004 bitweaver.org + * Copyright ( c ) 2003 tikwiki.org + * Copyright ( c ) 2002-2003, Luis Argerich, Garland Foster, Eduardo Polidor, et. al. + * All Rights Reserved. See copyright.txt for details and a complete list of authors. + * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details + * + * $Id: edit_pigeonholes.php,v 1.1 2005/08/21 16:22:41 squareing Exp $ + * @package pigeonholes + * @subpackage functions + */ + +/** + * required setup + */ +require_once( '../bit_setup_inc.php' ); + +$gBitSystem->verifyPackage( 'pigeonholes' ); +$gBitSystem->verifyPermission( 'bit_p_edit_pigeonholes' ); + +include_once( LIBERTY_PKG_PATH.'LibertyStructure.php' ); +include_once( PIGEONHOLES_PKG_PATH.'lookup_pigeonholes_inc.php' ); + +// include edit structure file only when structure_id is known +if( !empty( $_REQUEST["structure_id"] ) && ( empty( $_REQUEST['action'] ) || $_REQUEST['action'] != 'remove' ) ) { + $verifyStructurePermission = 'bit_p_edit_pigeonholes'; + include_once( LIBERTY_PKG_PATH.'edit_structure_inc.php' ); + + // get all the nodes in this structure + foreach( $rootTree as $node ) { + $pigeonStructure[$node['structure_id']] = str_repeat( '-', $node['level'] ).' '.$node['title']; + } + $gBitSmarty->assign( 'pigeonStructure', $pigeonStructure ); +} + +global $gStructure; + +//vd($_REQUEST); + +// store the form if we need to +if( !empty( $_REQUEST['pigeonhole_store'] ) ) { + if( ( empty( $_REQUEST['pigeonhole']['title'] ) ) ) { + $gBitSmarty->assign( 'msg', tra( "You must specify a title." ) ); + $gBitSystem->display( 'error.tpl' ); + die; + } + + // we need to get the root structure id + $_REQUEST['pigeonhole']['root_structure_id'] = !empty( $rootStructure->mStructureId ) ? $rootStructure->mStructureId : NULL; + // store the pigeonhole + $pigeonStore = new Pigeonholes(); + $pigeonStore->mContentId = !empty( $_REQUEST['content_id'] ) ? $_REQUEST['content_id'] : NULL; + $pigeonStore->load(); + if( $pigeonStore->store( $_REQUEST['pigeonhole'] ) ) { + header( "Location: ".$_SERVER['PHP_SELF'].'?structure_id='.$pigeonStore->mStructureId ); + } else { + vd( $gPigeonholes->mErrors ); + $gBitSmarty->assign( 'msg', tra( "There was a problem trying to store the pigeonhole." ) ); + $gBitSystem->display( 'error.tpl' ); + die; + } +} + +// if we are just changing the content that is being displayed, we treat it like a preview. +if( !empty( $_REQUEST['search_objects'] ) ) { + $pigeonInfo['parent_id'] = !empty( $_REQUEST['pigeonhole']['parent_id'] ) ? $_REQUEST['pigeonhole']['parent_id'] : NULL; + $pigeonInfo['title'] = !empty( $_REQUEST['pigeonhole']['title'] ) ? $_REQUEST['pigeonhole']['title'] : NULL; + $pigeonInfo['data'] = !empty( $_REQUEST['pigeonhole']['edit'] ) ? $_REQUEST['pigeonhole']['edit'] : NULL; + $pigeonInfo['selected_members'] = !empty( $_REQUEST['pigeonhole']['members'] ) ? $_REQUEST['pigeonhole']['members'] : NULL; + $gBitSmarty->assign( 'pigeonInfo', !empty( $pigeonInfo ) ? $pigeonInfo : NULL ); +} elseif( !empty( $_REQUEST['action'] ) || isset( $_REQUEST["confirm"] ) ) { + // if we need to edit, show the information + if( $_REQUEST['action'] == 'edit' ) { + $pigeonInfo = $gPigeonholes->mInfo; + + // create usable array for selected items in content listing + if( !empty( $pigeonInfo['members'] ) ) { + foreach( $pigeonInfo['members'] as $member ) { + if( $pigeonInfo['content_id'] == $member['parent_id'] ) { + $pigeonInfo['selected_members'][] = $member['content_id']; + } + } + } + } + + if( $_REQUEST['action'] == 'edit' || $_REQUEST['action'] == 'create' ) { + $gBitSmarty->assign( 'pigeonInfo', !empty( $pigeonInfo ) ? $pigeonInfo : NULL ); + } + + if( $_REQUEST['action'] == 'move' ) { + $gPigeonholes->moveMember( $_REQUEST['parent_id'], $_REQUEST['member_id'], $_REQUEST['orientation'] ); + } + + if( $_REQUEST["action"] == 'remove' || isset( $_REQUEST["confirm"] ) ) { + if( isset( $_REQUEST["confirm"] ) ) { + if( $gPigeonholes->expunge( $_REQUEST["structure_id"] ) ) { + header( "Location: ".$_SERVER['PHP_SELF'].'?structure_id='.$gPigeonholes->mInfo["parent_id"] ); + die; + } else { + vd( $gPigeonhole->mErrors ); + } + } + $gBitSystem->setBrowserTitle( 'Confirm removal of '.$gPigeonholes->mInfo['title'] ); + $formHash['remove'] = TRUE; + $formHash['structure_id'] = $_REQUEST['structure_id']; + $formHash['action'] = 'remove'; + $msgHash = array( + 'label' => 'Remove Pigeonhole', + 'confirm_item' => $gPigeonholes->mInfo['title'].'<br />and any subitems', + 'warning' => 'This will remove the pigeonhole but will <strong>not</strong> modify or remove the content itself.', + ); + $gBitSystem->confirmDialog( $formHash, $msgHash ); + } + + if( $_REQUEST['action'] == 'demember' && !empty( $_REQUEST['content_id'] ) && !empty( $_REQUEST['parent_id'] ) ) { + if( $gPigeonholes->expungePigeonholeMember( $_REQUEST['content_id'], $_REQUEST['parent_id'] ) ) { + $feedback['success'] = tra( 'The item was successfully removed' ); + } else { + $feedback['error'] = tra( 'The item could not be removed' ); + } + // used to avoid displaying edit form + unset( $_REQUEST['action'] ); + } +} + +// get content +include_once( LIBERTY_PKG_PATH.'get_content_list_inc.php' ); +foreach( $contentList['data'] as $cItem ) { + $cList[$contentTypes[$cItem['content_type_guid']]][$cItem['content_id']] = $cItem['title'].' [id: '.$cItem['content_id'].']'; +} +$gBitSmarty->assign( 'contentList', $cList ); +$gBitSmarty->assign( 'contentSelect', $contentSelect ); +$gBitSmarty->assign( 'contentTypes', $contentTypes ); + +$listHash['root_structure_id'] = $gPigeonholes->mInfo['root_structure_id']; +$pigeonList = $gPigeonholes->getList( $listHash, FALSE, TRUE ); +$gBitSmarty->assign( 'pigeonList', $pigeonList['data'] ); + +$gBitSmarty->assign( 'feedback', !empty( $feedback ) ? $feedback : NULL ); + +// Display the template +$gBitSystem->display( 'bitpackage:pigeonholes/edit_pigeonholes.tpl', !empty( $gStructure ) ? tra( 'Edit Pigeonhole' ).': '.$gStructure->mInfo["title"] : tra( 'Create Pigeonhole' ) ); +?> diff --git a/edit_structure.php b/edit_structure.php new file mode 100644 index 0000000..51f9101 --- /dev/null +++ b/edit_structure.php @@ -0,0 +1,31 @@ +<?php +/** + * $Header: /cvsroot/bitweaver/_bit_pigeonholes/edit_structure.php,v 1.1 2005/08/21 16:22:44 squareing Exp $ + * + * Copyright ( c ) 2004 bitweaver.org + * Copyright ( c ) 2003 tikwiki.org + * Copyright ( c ) 2002-2003, Luis Argerich, Garland Foster, Eduardo Polidor, et. al. + * All Rights Reserved. See copyright.txt for details and a complete list of authors. + * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details + * + * $Id: edit_structure.php,v 1.1 2005/08/21 16:22:44 squareing Exp $ + * @package pigeonholes + * @subpackage functions + */ + +/** + * required setup + */ +require_once( '../bit_setup_inc.php' ); + +$gBitSystem->verifyPackage( 'pigeonholes' ); +$gBitSystem->verifyPermission( 'bit_p_edit_pigeonholes' ); + +include_once( PIGEONHOLES_PKG_PATH.'lookup_pigeonholes_inc.php' ); + +$verifyStructurePermission = 'bit_p_edit_pigeonholes'; +include_once( LIBERTY_PKG_PATH.'edit_structure_inc.php' ); + +// Display the template +$gBitSystem->display( 'bitpackage:pigeonholes/edit_structure.tpl', $gStructure->mInfo["title"] ); +?> diff --git a/icons/organise.png b/icons/organise.png Binary files differnew file mode 100644 index 0000000..8df04ad --- /dev/null +++ b/icons/organise.png diff --git a/icons/pkg_pigeonholes.png b/icons/pkg_pigeonholes.png Binary files differnew file mode 100644 index 0000000..184e920 --- /dev/null +++ b/icons/pkg_pigeonholes.png diff --git a/index.php b/index.php new file mode 100644 index 0000000..ebdf752 --- /dev/null +++ b/index.php @@ -0,0 +1,25 @@ +<?php +/** + * $Header: /cvsroot/bitweaver/_bit_pigeonholes/index.php,v 1.1 2005/08/21 16:22:44 squareing Exp $ + * + * Copyright ( c ) 2004 bitweaver.org + * Copyright ( c ) 2003 tikwiki.org + * Copyright ( c ) 2002-2003, Luis Argerich, Garland Foster, Eduardo Polidor, et. al. + * All Rights Reserved. See copyright.txt for details and a complete list of authors. + * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details + * + * $Id: index.php,v 1.1 2005/08/21 16:22:44 squareing Exp $ + * @package pigeonholes + * @subpackage functions + */ + +/** + * required setup + */ +require_once( '../bit_setup_inc.php' ); +include_once( PIGEONHOLES_PKG_PATH.'lookup_pigeonholes_inc.php' ); +if( !empty( $gPigeonholes->mStructureId ) ) { + header( 'Location: '.PIGEONHOLES_PKG_URL.'view.php?structure_id='.$gPigeonholes->mStructureId ); +} else { + header( 'Location: '.PIGEONHOLES_PKG_URL.'list.php' ); +} diff --git a/list.php b/list.php new file mode 100644 index 0000000..06da14d --- /dev/null +++ b/list.php @@ -0,0 +1,49 @@ +<?php +/** + * $Header + * + * @author xing <xing@synapse.plus.com> + * @version $Revision: 1.1 $ + * @package pigeonholes + * @subpackage functions + */ + +/** + * required setup + */ +require_once("../bit_setup_inc.php"); + +$gBitSystem->verifyPackage( 'pigeonholes' ); +$gBitSystem->verifyPermission( 'bit_p_view_pigeonholes' ); + +include_once( PIGEONHOLES_PKG_PATH.'lookup_pigeonholes_inc.php' ); + +// some specific offsets and pagination settings +if( !empty( $_REQUEST['sort_mode'] ) ) { + $gBitSmarty->assign( 'sort_mode', $_REQUEST['sort_mode'] ); +} + +$gBitSmarty->assign( 'curPage', $page = !empty( $_REQUEST['page'] ) ? $_REQUEST['page'] : 1 ); +$listHash = array( + 'sort_mode' => !empty( $_REQUEST['sort_mode'] ) ? $_REQUEST['sort_mode'] : 'title_asc', + 'max_rows' => $gBitSystem->mPrefs['maxRecords'], + 'offset' => ( $page - 1 ) * $gBitSystem->mPrefs['maxRecords'], + 'find' => !empty( $_REQUEST['find'] ) ? $_REQUEST['find'] : NULL, +); + +$gBitSmarty->assign( 'pigeonList', $pigeonList = $gPigeonholes->getList( $listHash, TRUE, FALSE ) ); +$gBitSmarty->assign( 'numPages', ceil( $pigeonList['cant'] / $gBitSystem->mPrefs['maxRecords'] ) ); + +// set up structure related stuff +foreach( $pigeonList['data'] as $key => $pigeonhole ) { + $gStructure = new LibertyStructure( $pigeonhole['root_structure_id'] ); + $gStructure->load(); + $pigeonList['data'][$key]['subtree'] = $gStructure->getSubTree( $gStructure->mStructureId ); +} + +//$gBitSmarty->assign_by_ref('offset', $offset); +$gBitSmarty->assign( 'pigeonList', $pigeonList['data'] ); +$gBitSmarty->assign( 'pigeonCount', $pigeonList['cant'] ); + +$gBitSystem->display( 'bitpackage:pigeonholes/list.tpl', tra( 'List Pigeonholes' ) ); +?> diff --git a/lookup_pigeonholes_inc.php b/lookup_pigeonholes_inc.php new file mode 100644 index 0000000..2e14224 --- /dev/null +++ b/lookup_pigeonholes_inc.php @@ -0,0 +1,21 @@ +<?php +/** + * Provide a list of pigenoholes + * + * @package pigeonholes + * @subpackage functions + * @version $Header: /cvsroot/bitweaver/_bit_pigeonholes/lookup_pigeonholes_inc.php,v 1.1 2005/08/21 16:22:44 squareing Exp $ + * + * Copyright ( c ) 2005 bitweaver.org + * All Rights Reserved. See copyright.txt for details and a complete list of authors. + * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details + */ + +/** + * Required Files + */ +require_once( PIGEONHOLES_PKG_PATH.'/Pigeonholes.php' ); + +$gPigeonholes = new Pigeonholes( ( !empty( $_REQUEST['structure_id'] ) ? $_REQUEST['structure_id'] : NULL ), ( !empty( $_REQUEST['content_id'] ) ? $_REQUEST['content_id'] : NULL ), TRUE, TRUE ); +$gBitSmarty->assign( 'gPigeonholes', $gPigeonholes ); +?> diff --git a/servicefunctions_inc.php b/servicefunctions_inc.php new file mode 100644 index 0000000..6de9976 --- /dev/null +++ b/servicefunctions_inc.php @@ -0,0 +1,138 @@ +<?php +/** + * $Header: /cvsroot/bitweaver/_bit_pigeonholes/Attic/servicefunctions_inc.php,v 1.1 2005/08/21 16:22:39 squareing Exp $ + * + * Copyright ( c ) 2004 bitweaver.org + * All Rights Reserved. See copyright.txt for details and a complete list of authors. + * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details + * + * @package pigeonholes + * @subpackage functions + */ + +/** + * Pigeonhole display service + */ +function display_pigeonholes( &$pObject ) { + global $gBitSmarty, $gBitUser; + + if( $gBitUser->hasPermission( 'bit_p_view_pigeonholes' ) ) { + require_once( PIGEONHOLES_PKG_PATH.'Pigeonholes.php' ); + $pigeonholes = new Pigeonholes( NULL, NULL, FALSE ); + + if( $pigeons = $pigeonholes->getPigeonholesFromContentId( $pObject->mContentId ) ) { + foreach( $pigeons as $pigeon ) { + $pigeonholes->mContentId = $pigeon['content_id']; + $pigeonholes->load( TRUE ); + $pigeonData[] = $pigeonholes->mInfo; + } + $gBitSmarty->assign( 'pigeonData', !empty( $pigeonData ) ? $pigeonData : FALSE ); + } + } +} + +/** + * Pigeonhole edit template service + */ +function pigeonholes_input_content( $pObject=NULL ) { + global $gBitSmarty, $gBitUser; + $pigeonPathList = array(); + + if( $gBitUser->hasPermission( 'bit_p_insert_pigeonhole_member' ) ) { + require_once( PIGEONHOLES_PKG_PATH.'Pigeonholes.php' ); + $pigeonholes = new Pigeonholes( NULL, NULL, FALSE ); + + // get pigeonholes path list + if( $pigeonPathList = $pigeonholes->getPigeonholesPathList( !empty( $pObject->mContentId ) ? $pObject->mContentId : NULL ) ) { + $gBitSmarty->assign( 'pigeonPathList', $pigeonPathList ); + } + } +} + +/** + * Pigeonhole preview service + * when we hit preview, we make the selections persistent + */ +function pigeonholes_preview_content() { + global $gBitSmarty, $gBitUser; + $pigeonPathList = array(); + + if( $gBitUser->hasPermission( 'bit_p_insert_pigeonhole_member' ) ) { + require_once( PIGEONHOLES_PKG_PATH.'Pigeonholes.php' ); + $pigeonholes = new Pigeonholes( NULL, NULL, FALSE ); + + // get pigeonholes path list + if( $pigeonPathList = $pigeonholes->getPigeonholesPathList() ) { + foreach( $pigeonPathList as $key => $path ) { + if( !empty( $_REQUEST['pigeonholes']['pigeonhole'] ) && in_array( $key, $_REQUEST['pigeonholes']['pigeonhole'] ) ) { + $pigeonPathList[$key][0]['selected'] = TRUE; + } else { + $pigeonPathList[$key][0]['selected'] = FALSE; + } + } + $gBitSmarty->assign( 'pigeonPathList', $pigeonPathList ); + } + } +} + +/** + * Pigeonhole store service + * store the content in any pigeonhole it wants + */ +function pigeonholes_store_content( $pObject, $pParamHash ) { + global $gBitSmarty, $gBitUser; + if( $gBitUser->hasPermission( 'bit_p_insert_pigeonhole_member' ) ) { + require_once( PIGEONHOLES_PKG_PATH.'Pigeonholes.php' ); + + if( !empty( $pParamHash['content_id'] ) ) { + if( is_object( $pObject ) && empty( $pParamHash['content_id'] ) ) { + $pParamHash['content_id'] = $pObject->mContentId; + } + + $pigeonholes = new Pigeonholes( NULL, NULL, FALSE ); + $pigeonPathList = $pigeonholes->getPigeonholesPathList( $pParamHash['content_id'] ); + + // here we need to work out if we need to save at all + // get all originally selected items + $selectedItem = array(); + foreach( $pigeonPathList as $path ) { + if( !empty( $path[0]['selected'] ) ) { + $pathItem = array_pop( $path ); + $selectedItem[] = $pathItem['content_id']; + } + } + + // quick and dirty check to start off with + if( empty( $_REQUEST['pigeonholes'] ) || count( $_REQUEST['pigeonholes']['pigeonhole'] ) != count( $selectedItem ) ) { + $modified = TRUE; + } else { + // more thorough check + foreach( $selectedItem as $item ) { + if( !in_array( $item, $_REQUEST['pigeonholes']['pigeonhole'] ) ) { + $modified = TRUE; + } + } + } + + if( !empty( $modified ) ) { + // first remove all entries with this content_id + if( $pigeonholes->expungePigeonholeMember( NULL, $pParamHash['content_id'] ) && !empty( $_REQUEST['pigeonholes'] ) ) { + // insert the content into the desired pigeonholes + foreach( $_REQUEST['pigeonholes']['pigeonhole'] as $p_id ) { + $memberHash[] = array( + 'parent_id' => $p_id, + 'content_id' => $pParamHash['content_id'] + ); + } + + if( !$pigeonholes->insertPigeonholeMember( $memberHash ) ) { + $gBitSmarty->assign( 'msg', tra( "There was a problem inserting the content into the pigeonholes." ) ); + $gBitSystem->display( 'error.tpl' ); + die; + } + } + } + } + } +} +?> diff --git a/templates/admin_pigeonholes.tpl b/templates/admin_pigeonholes.tpl new file mode 100644 index 0000000..b80dfcb --- /dev/null +++ b/templates/admin_pigeonholes.tpl @@ -0,0 +1,29 @@ +{* $Header: /cvsroot/bitweaver/_bit_pigeonholes/templates/admin_pigeonholes.tpl,v 1.1 2005/08/21 16:22:47 squareing Exp $ *} +{strip} +{form} + {legend legend="Category Settings"} + <input type="hidden" name="page" value="{$page}" /> + {foreach from=$pigeonholeSettings key=feature item=output} + <div class="row"> + {formlabel label=`$output.label` for=$feature} + {forminput} + {html_checkboxes name="$feature" values="y" checked=`$gBitSystemPrefs.$feature` labels=false id=$feature} + {formhelp note=`$output.note` page=`$output.page`} + {/forminput} + </div> + {/foreach} + + <div class="row"> + {formlabel label="Number of Members" for="member_number"} + {forminput} + {html_options name="limit_member_number" options=$memberLimit values=$memberLimit selected=`$gBitSystemPrefs.limit_member_number` id=member_number} + {formhelp note="Here you can specify what number of members are displayed at the bottom of a page."} + {/forminput} + </div> + + <div class="row submit"> + <input type="submit" name="pigeonhole_settings" value="{tr}Change preferences{/tr}" /> + </div> + {/legend} +{/form} +{/strip} diff --git a/templates/assign_non_members.tpl b/templates/assign_non_members.tpl new file mode 100644 index 0000000..31437dc --- /dev/null +++ b/templates/assign_non_members.tpl @@ -0,0 +1,112 @@ +{strip} +<div class="edit pigeonholes"> + <div class="header"> + <h1>{tr}Assign Content to Categories{/tr}</h1> + </div> + + <div class="body"> + {if !$pigeonList} + {formfeedback warning="No categories have been set up yet. You need to create some before you can assign content to them."} + {else} + {form legend="Assign Content"} + <input type="hidden" name="sort_mode" value="{$smarty.request.sort_mode}" /> + <div class="row"> + {formlabel label="Restrict listing" for="content_type"} + + {forminput} + <select name="max_rows"> + <option>{tr}All{/tr}</option> + <option value="50" {if $smarty.request.max_rows eq 50}selected="selected"{/if}>{tr}50{/tr}</option> + <option value="100" {if $smarty.request.max_rows eq 100 or !$smarty.request.max_rows}selected="selected"{/if}>{tr}100{/tr}</option> + <option value="200" {if $smarty.request.max_rows eq 200}selected="selected"{/if}>{tr}200{/tr}</option> + <option value="500" {if $smarty.request.max_rows eq 500}selected="selected"{/if}>{tr}500{/tr}</option> + </select> {tr}Records{/tr} + {/forminput} + + {forminput} + <select name="include"> + <option value="">{tr}Hide assigned content{/tr}</option> + <option value="members" {if $smarty.request.include eq 'members'}selected="selected"{/if}>{tr}Display assigned content{/tr}</option> + </select> + {/forminput} + + {forminput} + {html_options values=$contentTypes options=$contentTypes name=content_type id=content_type selected=$contentSelect} + {/forminput} + + {forminput} + <input type="text" value="{$smarty.request.find_objects}" name="find_objects" /> + {formhelp note="You can restrict the content listing to a given content type or apply a filter."} + {/forminput} + </div> + + <div class="row submit"> + <input type="submit" value="{tr}Restrict Listing{/tr}" name="search_objects" /> + </div> + {/form} + + {formfeedback hash=$feedback} + + {form} + <input type="hidden" name="sort_mode" value="{$smarty.request.sort_mode}" /> + <input type="hidden" name="include" value="{$smarty.request.include}" /> + <input type="hidden" name="find_objects" value="{$smarty.request.find_objects}" /> + <input type="hidden" name="content_type" value="{$contentSelect}" /> + + {if $gBitSystem->isFeatureActive( 'custom_member_sorting' ) && $smarty.request.include eq 'members'} + {formfeedback warning="Using this insertion method will reset any custom sorting you have done so far."} + {/if} + + <table class="data"> + <caption>{tr}Available Content{/tr} <span class="total">[ {$contentCount} ]</span></caption> + <tr> + <th>{smartlink ititle="Title" isort=title idefault=1 max_rows=$smarty.request.max_rows content_type=$contentSelect find_objects=$find_objects include=$smarty.request.include page=$page}</th> + <th>{smartlink ititle="Content Type" isort=content_type_guid max_rows=$smarty.request.max_rows content_type=$contentSelect find_objects=$find_objects include=$smarty.request.include page=$page}</th> + {if $nonMembers} + {foreach from=$pigeonList item=pigeon} + <th><abbr title="{$pigeon.title}">{counter}</abbr></th> + {/foreach} + {/if} + </tr> + + {foreach from=$nonMembers item=item} + <tr class="{cycle values='odd,even'}"> + <td><a href="{$smarty.const.BIT_ROOT_URL}index.php?content_id={$item.content_id}">{$item.title}</a></td> + <td>{assign var=content_type_guid value=`$item.content_type_guid`}{$contentTypes.$content_type_guid}</td> + {foreach from=$pigeonList item=pigeon} + <td style="text-align:center"> + <input type="checkbox" name="pigeonhole[{$item.content_id}][]" value="{$pigeon.content_id}" + {foreach from=$item.assigned item=parent_id} + {if $pigeon.content_id eq $parent_id}checked="checked"{/if} + {/foreach} + title="{$pigeon.title}" /> + </td> + {/foreach} + </tr> + {foreachelse} + <tr> + <td colspan="2" class="norecords">{tr}No Content can be found with your selection criteria{/tr}</td> + </tr> + {/foreach} + </table> + + {if $nonMembers} + <div class="row submit"> + <input type="submit" name="insert_content" value="Insert Content into Categories" /> + </div> + {/if} + {/form} + + {if $nonMembers} + {foreach from=$pigeonList item=pigeon} + <dl> + <dt>{counter name=dogEatsPigeon}</dt> + <dd>{$pigeon.display_path}<br /><small>{$pigeon.data|escape}</small></dd> + </dl> + {/foreach} + {/if} + {/if} + </div><!-- end .body --> +</div><!-- end .liberty --> +{/strip} + diff --git a/templates/display_members.tpl b/templates/display_members.tpl new file mode 100644 index 0000000..b34d290 --- /dev/null +++ b/templates/display_members.tpl @@ -0,0 +1,54 @@ +{strip} +<div class="display pigeonholes"> + {if $gBitSystem->isFeatureActive( 'display_pigeonhole_members' ) and $pigeonData} + <h2>{tr}Related Items{/tr}</h2> + {foreach from=$pigeonData item=pigeonItem} + <div class="box"> + <h3>{$pigeonItem.display_path}</h3> + + <div class="boxcontent"> + {if $pigeonItem.data and $gBitSystem->isFeatureActive( 'display_pigeonhole_description' )} + {$pigeonItem.data}<br /> + {/if} + + {* reset vars *} + {counter start=0 assign=member_count} + {assign var=more value=0} + + {if $gBitSystem->isFeatureActive( 'custom_member_sorting' )} + {foreach from=$pigeonItem.members item=member} + {if !$gBitSystemPrefs.limit_member_number or $member_count lt $gBitSystemPrefs.limit_member_number} + <a href="{$smarty.const.BIT_ROOT_URL}index.php?content_id={$member.content_id}">{$member.title}</a> • + {else} + {assign var=more value=1} + {/if} + {counter assign=member_count} + {/foreach} + {else} + {foreach from=$pigeonItem.members item=member} + {assign var=ctg1 value=$member.content_type_guid} + + {if $ctg1 ne $ctg2}{if $ctg2}<br />{/if}{$gLibertySystem->mContentTypes.$ctg1.content_description}: {/if} + + {if !$gBitSystemPrefs.limit_member_number or $member_count lt $gBitSystemPrefs.limit_member_number} + <a href="{$smarty.const.BIT_ROOT_URL}index.php?content_id={$member.content_id}">{$member.title}</a> • + {else} + {assign var=more value=1} + {/if} + + {counter assign=member_count} + {assign var=ctg2 value=$member.content_type_guid} + {/foreach} + {/if} + + {if $more eq 1} + <a href="{$smarty.const.PIGEONHOLES_PKG_URL}view.php?structure_id={$pigeonItem.structure_id}">[ … ]</a> + {/if} + </div> + </div> + {* reset the ctg2 value *} + {assign var=ctg2 value=''} + {/foreach} + {/if} +</div> +{/strip} diff --git a/templates/display_paths.tpl b/templates/display_paths.tpl new file mode 100644 index 0000000..eed90a5 --- /dev/null +++ b/templates/display_paths.tpl @@ -0,0 +1,9 @@ +{strip} +{if $gBitSystem->isFeatureActive( 'display_pigeonhole_path' )} + <div class="structurebar pigeonholesbar"> + {foreach from=$pigeonData item=pigeonItem} + <span class="path">{$pigeonItem.display_path}</span> + {/foreach} + </div><!-- end .structurebar --> +{/if} +{/strip} diff --git a/templates/edit_pigeonholes.tpl b/templates/edit_pigeonholes.tpl new file mode 100644 index 0000000..ed2f2a2 --- /dev/null +++ b/templates/edit_pigeonholes.tpl @@ -0,0 +1,19 @@ +<div class="floaticon">{bithelp}</div> + +<div class="edit pigeonholes"> + <div class="header"> + <h1>{tr}Edit Categories{/tr}</h1> + </div> + + <div class="body"> + {formfeedback hash=$feedback} + {if $gBitUser->hasPermission( 'bit_p_edit_pigeonholes' ) and ( $smarty.request.action eq 'create' or $smarty.request.action eq 'edit' or !$gPigeonholes->mContentId )} + {include file="bitpackage:pigeonholes/edit_pigeonholes_inc.tpl"} + {elseif $gBitUser->hasPermission( 'bit_p_edit_pigeonholes' )} + {smartlink ititle="Insert new Category" ifile="edit_pigeonholes.php" structure_id=`$gPigeonholes->mStructureId` action=create} + <br /> + {/if} + + {include file="bitpackage:pigeonholes/view_structure_inc.tpl" edit=true} + </div><!-- end .body --> +</div><!-- end .edit --> diff --git a/templates/edit_pigeonholes_inc.tpl b/templates/edit_pigeonholes_inc.tpl new file mode 100644 index 0000000..db2ce32 --- /dev/null +++ b/templates/edit_pigeonholes_inc.tpl @@ -0,0 +1,55 @@ +{form legend="Create / Edit Category"} + {if $gPigeonholes->mStructureId} + <input type="hidden" name="structure_id" value="{$gPigeonholes->mStructureId}" /> + <input type="hidden" name="content_id" value="{$pigeonInfo.content_id}" /> + <input type="hidden" name="action" value="{$smarty.request.action}" /> + + <div class="row"> + {formlabel label="Parent" for="pigeonhole-parent"} + {forminput} + {* we need to disable dropdown when editing since it might confus users when nothing happens *} + {if $pigeonInfo.content_id} + {html_options id="pigeonhole-parent" name="pigeonhole[parent_id]" values=$pigeonStructure options=$pigeonStructure selected=$pigeonInfo.parent_id disabled=disabled} + {else} + {html_options id="pigeonhole-parent" name="pigeonhole[parent_id]" values=$pigeonStructure options=$pigeonStructure selected=$pigeonInfo.parent_id} + {/if} + {formhelp note="Pick where you would like to create a new sub-category. To change the hierarchy of the categories, please visit the change structure page."} + {/forminput} + </div> + {/if} + + <div class="row"> + {formlabel label="Title" for="pigeonhole-title"} + {forminput} + <input type="text" size="50" id="pigeonhole-title" name="pigeonhole[title]" value="{$pigeonInfo.title}" /> + {/forminput} + </div> + + <div class="row"> + {formlabel label="Description" for="pigeonhole-desc"} + {forminput} + <textarea id="pigeonhole-desc" name="pigeonhole[edit]" rows="3" cols="80">{$pigeonInfo.data|escape}</textarea> + {formhelp note="A description of the category. This will be visible when users view this particular category."} + {/forminput} + </div> + + <div class="row"> + {formlabel label="Content" for="pigeonhole-content"} + {forminput} + {html_options values=$contentTypes options=$contentTypes name=content_type_guid selected=$contentSelect} + {/forminput} + + {forminput} + {html_options multiple="multiple" size="12" name="pigeonhole[members][]" id="pigeonhole-content" values=$contentList options=$contentList selected=$pigeonInfo.selected_members} + {/forminput} + + {forminput} + <input type="text" name="find_objects" value="{$smarty.request.find_objects}" /> + <input type="submit" value="{tr}Apply filter{/tr}" name="search_objects" /> + {/forminput} + </div> + + <div class="row submit"> + <input type="submit" name="pigeonhole_store" value="{tr}Save Category{/tr}" /> + </div> +{/form} diff --git a/templates/edit_structure.tpl b/templates/edit_structure.tpl new file mode 100644 index 0000000..196637f --- /dev/null +++ b/templates/edit_structure.tpl @@ -0,0 +1,11 @@ +<div class="floaticon">{bithelp}</div> + +<div class="edit pigeonholes"> + <div class="header"> + <h1>{tr}Edit Category Hierarchy{/tr}</h1> + </div> + + <div class="body"> + {include file="bitpackage:liberty/edit_structure_inc.tpl" hide_extended=TRUE} + </div><!-- end .body --> +</div><!-- end .edit --> diff --git a/templates/list.tpl b/templates/list.tpl new file mode 100644 index 0000000..4ac7f87 --- /dev/null +++ b/templates/list.tpl @@ -0,0 +1,55 @@ +{strip} +<div class="listing pigeonholes"> + <div class="header"> + <h1>{tr}Categories Listing{/tr}</h1> + </div> + + {* user sort related assigning *} + {if $gBitSystem->isFeatureActive( 'display_name' ) eq login} + {assign var=isort_author value=creator_user} + {assign var=isort_editor value=modifier_user} + {else} + {assign var=isort_author value=creator_real_name} + {assign var=isort_editor value=modifier_real_name} + {/if} + + <div class="body"> + {minifind} + + <table class="data"> + <caption>{tr}Available Categories{/tr} <span class="total">[ {$pigeonCount} ]</span></caption> + <tr> + <th>{smartlink ititle="Title" isort=title page=$page idefault=1} / {smartlink ititle="Description" isort=data page=$page}</th> + <th>{tr}Categories{/tr}</th> + {if $gBitUser->hasPermission( 'bit_p_edit_pigeonholes' )} + <th>{tr}Actions{/tr}</th> + {/if} + </tr> + + {foreach from=$pigeonList item=item} + <tr class="{cycle values='odd,even'}"> + <td> + <h2>{$item.display_link}</h2> + {$item.data} + </td> + <td>{include file="bitpackage:pigeonholes/view_structure_inc.tpl" plain=true subtree=$item.subtree}</td> + {if $gBitUser->hasPermission( 'bit_p_edit_pigeonholes' )} + <td class="actionicon"> + {smartlink ititle="Insert new Category" ifile="edit_pigeonholes.php" ibiticon="liberty/new" structure_id=`$item.structure_id` action=create} + {smartlink ititle="Edit Category" ifile="edit_pigeonholes.php" ibiticon="liberty/edit" structure_id=`$item.structure_id`} + {smartlink ititle="Change Structure" ifile="edit_structure.php" ibiticon="pigeonholes/organise" structure_id=`$item.structure_id`} + {smartlink ititle="Remove Category" ifile="edit_pigeonholes.php" ibiticon="liberty/delete" action="remove" structure_id=`$item.structure_id`} + </td> + {/if} + </tr> + {foreachelse} + <tr class="norecords"> + <td colspan="5">{tr}No Records Found{/tr}</td> + </tr> + {/foreach} + </table> + + {libertypagination numPages=$numPages page=$curPage sort_mode=$sort_mode content_type=$contentSelect user_id=$user_id} + </div><!-- end .body --> +</div><!-- end .liberty --> +{/strip} diff --git a/templates/menu_pigeonholes.tpl b/templates/menu_pigeonholes.tpl new file mode 100644 index 0000000..cf96345 --- /dev/null +++ b/templates/menu_pigeonholes.tpl @@ -0,0 +1,26 @@ +{strip} +<ul> + {if $gBitUser->hasPermission( 'bit_p_edit_pigeonholes' )} + <li><a class="item" href="{$smarty.const.PIGEONHOLES_PKG_URL}edit_pigeonholes.php?action=create">{biticon ipackage=liberty iname=new iexplain="Create Category"} {tr}Create Category{/tr}</a></li> + {/if} + + {if $gBitUser->hasPermission( 'bit_p_view_pigeonholes' )} + <li><a class="item" href="{$smarty.const.PIGEONHOLES_PKG_URL}list.php">{biticon ipackage=liberty iname=list iexplain="List Categories"} {tr}List Categories{/tr}</a></li> + {if $gPigeonholes->mStructureId} + <li><a class="item" href="{$smarty.const.PIGEONHOLES_PKG_URL}view.php?structure_id={$gPigeonholes->mStructureId}">{biticon ipackage=liberty iname=spacer iexplain=""} {tr}View Category{/tr}</a></li> + {if $gBitUser->hasPermission( 'bit_p_edit_pigeonholes' ) and $gPigeonholes->mStructureId} + <li><a class="head" href="{$smarty.const.PIGEONHOLES_PKG_URL}edit_pigeonholes.php?structure_id={$gPigeonholes->mInfo.structure_id}">{biticon ipackage=liberty iname=edit iexplain="Edit Category"} {tr}Edit Category{/tr}</a> + <ul> + <li><a class="item" href="{$smarty.const.PIGEONHOLES_PKG_URL}edit_pigeonholes.php?structure_id={$gPigeonholes->mInfo.root_structure_id}&action=create">{biticon ipackage=liberty iname=new iexplain="Insert Category"} {tr}Insert Category{/tr}</a></li> + <li><a class="item" href="{$smarty.const.PIGEONHOLES_PKG_URL}edit_structure.php?structure_id={$gPigeonholes->mInfo.structure_id}">{biticon ipackage=pigeonholes iname=organise iexplain="Change Structure"} {tr}Change Structure{/tr}</a></li> + </ul> + </li> + {/if} + {/if} + {/if} + + {if $gBitUser->hasPermission( 'bit_p_insert_pigeonholes' )} + <li><a class="item" href="{$smarty.const.PIGEONHOLES_PKG_URL}assign_non_members.php">{biticon ipackage=liberty iname=assign iexplain="Assign Content"} {tr}Assign Content{/tr}</a></li> + {/if} +</ul> +{/strip} diff --git a/templates/menu_pigeonholes_admin.tpl b/templates/menu_pigeonholes_admin.tpl new file mode 100644 index 0000000..3e62101 --- /dev/null +++ b/templates/menu_pigeonholes_admin.tpl @@ -0,0 +1 @@ +<ul><li>{smartlink ititle="Pigeonhole Settings" ipackage="kernel" ifile="admin/index.php" page="pigeonholes"}</li></ul> diff --git a/templates/pigeonholes_input_inc.tpl b/templates/pigeonholes_input_inc.tpl new file mode 100644 index 0000000..2172113 --- /dev/null +++ b/templates/pigeonholes_input_inc.tpl @@ -0,0 +1,18 @@ +{strip} +{if $pigeonPathList} + <div class="row"> + {formlabel label="Pick Categories"} + {forminput} + {foreach from=$pigeonPathList key=pigeonId item=path} + <label> + <input type="checkbox" value="{$pigeonId}" {if $path.0.selected}checked="checked" {/if}name="pigeonholes[pigeonhole][]" /> + {foreach from=$path item=node} + {if $node.parent_id} »{/if} {$node.title} + {/foreach} + <br /> + </label> + {/foreach} + {/forminput} + </div> +{/if} +{/strip} diff --git a/templates/structure_section_inc.tpl b/templates/structure_section_inc.tpl new file mode 100644 index 0000000..d60f6a9 --- /dev/null +++ b/templates/structure_section_inc.tpl @@ -0,0 +1,97 @@ +{strip} +{if $gPigeonholes->mStructureId eq $subtree[ix].structure_id or $smarty.request.expand_all} + {assign var=iname value=Expanded} +{else} + {assign var=iname value=Collapsed} +{/if} + +<div class="highlight"> + {if $edit} + <div class="floaticon"> + {smartlink ititle="Edit Category" ibiticon="liberty/edit" ifile="edit_pigeonholes.php" structure_id=$subtree[ix].structure_id action=edit} + {smartlink ititle="Remove Category" ibiticon="liberty/delete" ifile="edit_pigeonholes.php" structure_id=$subtree[ix].structure_id action=remove} + </div> + {/if} + + <a href="javascript:icntoggle('sid{$subtree[ix].structure_id}');"> + {biticon ipackage=liberty iname=$iname id=sid`$subtree[ix].structure_id`img"} {$subtree[ix].title} + </a> + + <script type="text/javascript"> + setfoldericonstate('sid{$subtree[ix].structure_id}'); + </script> + + {foreach from=$pigeonList item=pigeonItem} + {if $pigeonItem.structure_id eq $subtree[ix].structure_id} + <small> {tr}{$pigeonItem.members_count} Item(s){/tr} </small> + {/if} + {/foreach} + + <noscript> + <div style="padding-left:18px;" class="small"><a href="{$smarty.const.PIGEONHOLES_PKG_URL}{if $edit}edit_pigeonholes{else}index{/if}.php?structure_id={$subtree[ix].structure_id}">{tr}Expand{/tr}</a></div> + </noscript> +</div> + +{foreach from=$pigeonList item=pigeonItem} + {if $pigeonItem.structure_id eq $subtree[ix].structure_id} + <small>{$pigeonItem.data|escape}</small> + + {if $pigeonItem.members} + <ul id="sid{$subtree[ix].structure_id}" style="display:{if $gPigeonholes->mStructureId eq $subtree[ix].structure_id or $smarty.request.expand_all}block{else}none{/if};" class="data"> + {foreach from=$pigeonItem.members item=pigeonMember} + {if $gBitSystem->isFeatureActive( 'custom_member_sorting' )} + <li> + {if $edit && $gBitSystem->isFeatureActive( 'custom_member_sorting' )} + {if $pigeonMember.pos ne 1} + {smartlink ititle="Move item up" ibiticon="liberty/nav_up" expand_all=$smarty.request.expand_all ifile="edit_pigeonholes.php" action=move orientation=north structure_id=$pigeonItem.structure_id parent_id=$pigeonItem.content_id member_id=$pigeonMember.content_id} + {else} + {biticon ipackage="liberty" iname="spacer"} + {/if} + + {if $pigeonMember.pos ne $pigeonItem.members_count} + {smartlink ititle="Move item down" ibiticon="liberty/nav_down" expand_all=$smarty.request.expand_all ifile="edit_pigeonholes.php" action=move orientation=south structure_id=$pigeonItem.structure_id parent_id=$pigeonItem.content_id member_id=$pigeonMember.content_id} + {else} + {biticon ipackage="liberty" iname="spacer"} + {/if} + {/if} + <a href="{$smarty.const.BIT_ROOT_URL}index.php?content_id={$pigeonMember.content_id}">{$pigeonMember.title}</a> + {if $edit} + {smartlink ititle="Remove Item" ibiticon="liberty/delete_small" expand_all=$smarty.request.expand_all ifile="edit_pigeonholes.php" action=demember structure_id=$pigeonItem.structure_id parent_id=$pigeonMember.content_id content_id=$pigeonItem.content_id} + {/if} + </li> + {else} + {assign var=ctg1 value=$pigeonMember.content_type_guid} + + {* close off the content type <ul> *} + {if $ctg1 ne $ctg2 and $ctg2} + </ul> + </li> + {/if} + + {* open the content type <ul> *} + {if $ctg1 ne $ctg2} + <li>{$gLibertySystem->mContentTypes.$ctg1.content_description} + <ul> + {/if} + + <li> + <a href="{$smarty.const.BIT_ROOT_URL}index.php?content_id={$pigeonMember.content_id}">{$pigeonMember.title}</a> + {if $edit} + {smartlink ititle="Remove Item" ibiticon="liberty/delete_small" expand_all=$smarty.request.expand_all ifile="edit_pigeonholes.php" action=demember structure_id=$pigeonItem.structure_id parent_id=$pigeonMember.content_id content_id=$pigeonItem.content_id} + {/if} + </li> + + {assign var=ctg2 value=$pigeonMember.content_type_guid} + {/if} + {/foreach} + + {* close any open uls and lis *} + {if !$gBitSystem->isFeatureActive( 'custom_member_sorting' )} + </ul> + </li> + {/if} + </ul> + {/if} + {/if} +{/foreach} +{/strip} diff --git a/templates/view_structure.tpl b/templates/view_structure.tpl new file mode 100644 index 0000000..a53a3fb --- /dev/null +++ b/templates/view_structure.tpl @@ -0,0 +1,15 @@ +{strip} +<div class="display pigeonholes"> + <div class="header"> + <h1>{tr}Categories Listing{/tr}</h1> + </div> + + <div class="body"> + {if !$smarty.request.expand_all and !( $smarty.request.action eq 'edit' or $smarty.request.action eq 'create' )} + {smartlink ititle="Expand All" expand_all=1 structure_id=$gPigeonholes->mStructureId} + {/if} + + {include file="bitpackage:pigeonholes/view_structure_inc.tpl"} + </div><!-- end .body --> +</div><!-- end .liberty --> +{/strip} diff --git a/templates/view_structure_inc.tpl b/templates/view_structure_inc.tpl new file mode 100644 index 0000000..164685a --- /dev/null +++ b/templates/view_structure_inc.tpl @@ -0,0 +1,26 @@ +{strip} +<ul class="toc"> + <li> + {section name=ix loop=$subtree} + {assign var=structId value=$subtree[ix].structure_id} + {if $subtree[ix].pos eq ''} + {if $plain} + {$subtree[ix].title} + {else} + {include file="bitpackage:pigeonholes/structure_section_inc.tpl"} + {/if} + {else} + {if $subtree[ix].first}<ul>{else}</li>{/if} + {if $subtree[ix].last}</ul>{else} + <li> + {if $plain} + {$subtree[ix].title} + {else} + {include file="bitpackage:pigeonholes/structure_section_inc.tpl"} + {/if} + {/if} + {/if} + {/section} + </li> +</ul><!-- end outermost .toc --> +{/strip} diff --git a/view.php b/view.php new file mode 100644 index 0000000..898c77e --- /dev/null +++ b/view.php @@ -0,0 +1,46 @@ +<?php +/** + * $Header: /cvsroot/bitweaver/_bit_pigeonholes/view.php,v 1.1 2005/08/21 16:22:45 squareing Exp $ + * + * Copyright ( c ) 2004 bitweaver.org + * Copyright ( c ) 2003 tikwiki.org + * Copyright ( c ) 2002-2003, Luis Argerich, Garland Foster, Eduardo Polidor, et. al. + * All Rights Reserved. See copyright.txt for details and a complete list of authors. + * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details + * + * $Id: view.php,v 1.1 2005/08/21 16:22:45 squareing Exp $ + * @package pigeonholes + * @subpackage functions + */ + +/** + * required setup + */ +require_once( '../bit_setup_inc.php' ); + +$gBitSystem->verifyPackage( 'pigeonholes' ); +$gBitSystem->verifyPermission( 'bit_p_view_pigeonholes' ); + +include_once( PIGEONHOLES_PKG_PATH.'lookup_pigeonholes_inc.php' ); + +// set up structure related stuff +global $gStructure; +$gStructure = new LibertyStructure( $gPigeonholes->mInfo['root_structure_id'] ); +$gStructure->load(); + +// order matters for these conditionals +if( empty( $gStructure ) || !$gStructure->isValid() ) { + $gBitSystem->fatalError( 'Invalid structure' ); +} + +$gBitSmarty->assign_by_ref( 'gStructure', $gStructure ); +$gBitSmarty->assign( 'structureInfo', $gStructure->mInfo ); +$gBitSmarty->assign( 'subtree', $gStructure->getSubTree( $gStructure->mStructureId ) ); + +$listHash = array( 'root_structure_id' => $gPigeonholes->mInfo['root_structure_id'] ); +$pigeonList = $gPigeonholes->getList( $listHash, FALSE, TRUE ); +$gBitSmarty->assign( 'pigeonList', $pigeonList['data'] ); + +// Display the template +$gBitSystem->display( 'bitpackage:pigeonholes/view_structure.tpl', tra( 'View Pigeonhole' ) ); +?> |
