[TYPO3-core] RFC: Feature #4923: provide new inputfield "directorypicker" in BE

Ralf Hettinger ng at ralfhettinger.de
Fri Feb 8 10:48:23 CET 2008


ToDo for integration into 4.2:

Solve handling of link in TCEForm to wizard from single input fields properly.
The link should be built by appending ?mode=wizard&act=folder or similar to
that. Currently it uses mode=folder and results in JavaScript-Errors.

For testing the wizard with an input field, you can simply use Andreas dirpicker
demo extension at http://bugs.typo3.org/file_download.php?file_id=2455&type=bug

Ralf

Ralf Hettinger schrieb:
> This is an SVN patch request.
> 
> Type: New feature
> 
> Bugtracker references:
> http://bugs.typo3.org/view.php?id=4923
> 
> Branches:
> trunk only
> 
> Problem:
> Extend TCA-types with the possibilty to select a directory instead of only
> picking a file. Could be used for e.g. Galleries, Filelists etc.
> 
> Solution:
> This solution is initially provided by Andreas Wolf (thank you!)
> With attached patch, the following is possible by TCA
> [...]
> 'config' => Array (
> 	'type'=>'group',
> 	'internal_type'=>'folder',
> [...]
> ),
> [...]
> 
> There is a .t3x by Andreas attached as "dirpicker"-demo to the bugreport for
> easy demonstration what it does.
> 
> Notes:
> I haven't tested the patch heavily (though I _have_ tested it with the current
> trunk). The original reporter redacted user just passed a request to me couple
> of days ago for this feature to be included in 4.2 since this "dirpicker" seemed
> top be quite well accepted.
> Thanks for reminding, Boris.
> 
> Ralf Hettinger
> 
> 
> ------------------------------------------------------------------------
> 
> Index: t3lib/class.t3lib_tceforms.php
> ===================================================================
> --- t3lib/class.t3lib_tceforms.php	(revision 2950)
> +++ t3lib/class.t3lib_tceforms.php	(working copy)
> @@ -2026,6 +2026,23 @@
>  					if ($this->edit_docModuleUpload)	$item.='<input type="file" name="'.$PA['itemFormElName_file'].'"'.$this->formWidth().' size="60" />';
>  				}
>  			break;
> +			case 'folder':	// If the element is of the internal type "folder":
> +
> +					// array of file items:
> +				$itemArray = t3lib_div::trimExplode(',',$PA['itemFormElValue'],1);
> +
> +					// Creating the element:
> +				$params = array(
> +					'size' => $size,
> +					'dontShowMoveIcons' => ($maxitems<=1),
> +					'autoSizeMax' => t3lib_div::intInRange($config['autoSizeMax'],0),
> +					'maxitems' => $maxitems,
> +					'style' => isset($config['selectedListStyle']) ? ' style="'.htmlspecialchars($config['selectedListStyle']).'"' : ' style="'.$this->defaultMultipleSelectorStyle.'"',
> +					'info' => $info,
> +					'readOnly' => $disabled
> +				);
> +				$item.= $this->dbFileIcons($PA['itemFormElName'],'folder','',$itemArray,'',$params,$PA['onFocus']);
> +			break;
>  			case 'db':	// If the element is of the internal type "db":
>  
>  					// Creating string showing allowed types:
> @@ -3296,6 +3313,7 @@
>  					}
>  				break;
>  				case 'file':
> +				case 'folder':
>  					while(list(,$pp)=each($itemArray))	{
>  						$pParts = explode('|',$pp);
>  						$uidList[]=$pUid=$pTitle = $pParts[0];
> Index: typo3/class.browse_links.php
> ===================================================================
> --- typo3/class.browse_links.php	(revision 2950)
> +++ typo3/class.browse_links.php	(working copy)
> @@ -882,24 +882,26 @@
>  			}
>  		';
>  
> -
> -		if ($this->mode=='wizard')	{	// Functions used, if the link selector is in wizard mode (= TCEforms fields)
> +		$P2=array();
> +		$P2['itemName']=$this->P['itemName'];
> +		$P2['formName']=$this->P['formName'];
> +		$P2['fieldChangeFunc']=$this->P['fieldChangeFunc'];
> +		$P2['params']['allowedExtensions']=$this->P['params']['allowedExtensions'];
> +		$P2['params']['blindLinkOptions']=$this->P['params']['blindLinkOptions'];
> +		$addPassOnParams.=t3lib_div::implodeArrayForUrl('P',$P2);
> +		$update='';
> +		if (is_array($this->P['fieldChangeFunc'])) {
>  			unset($this->P['fieldChangeFunc']['alert']);
>  			reset($this->P['fieldChangeFunc']);
> -			$update='';
>  			while(list($k,$v)=each($this->P['fieldChangeFunc']))	{
> -				$update.= '
> -				window.opener.'.$v;
> +				if (trim($v)) {
> +					$update.= '
> +					window.opener.'.$v;
> +				}
>  			}
> +		}
>  
> -			$P2=array();
> -			$P2['itemName']=$this->P['itemName'];
> -			$P2['formName']=$this->P['formName'];
> -			$P2['fieldChangeFunc']=$this->P['fieldChangeFunc'];
> -			$P2['params']['allowedExtensions']=$this->P['params']['allowedExtensions'];
> -			$P2['params']['blindLinkOptions']=$this->P['params']['blindLinkOptions'];
> -			$addPassOnParams.=t3lib_div::implodeArrayForUrl('P',$P2);
> -
> +		if ($this->mode=='wizard' || $this->mode=='folder')	{	// Functions used, if the link selector is in wizard mode (= TCEforms fields or simple input field used as dirpicker)
>  			$JScode.='
>  				function link_typo3Page(id,anchor)	{	//
>  					updateValueInMainForm(id+(anchor?anchor:"")+" "+cur_target);
> @@ -921,12 +923,10 @@
>  					}
>  					return false;
>  				}
> -				function checkReference()	{	//
> -					if (window.opener && window.opener.document && window.opener.document.'.$this->P['formName'].' && window.opener.document.'.$this->P['formName'].'["'.$this->P['itemName'].'"] )	{
> -						return window.opener.document.'.$this->P['formName'].'["'.$this->P['itemName'].'"];
> -					} else {
> -						close();
> -					}
> +				function set_folderpath(folder) {	//
> +					updateValueInMainForm(folder);
> +					close();
> +					return false;
>  				}
>  				function updateValueInMainForm(input)	{	//
>  					var field = checkReference();
> @@ -936,7 +936,18 @@
>  					}
>  				}
>  			';
> -		} else {	// Functions used, if the link selector is in RTE mode:
> +			if ($this->P['formName'] && $this->P['itemName']) {
> +				$JScode.='
> +					function checkReference()	{	//
> +						if (window.opener && window.opener.document && window.opener.document.'.$this->P['formName'].' && window.opener.document.'.$this->P['formName'].'["'.$this->P['itemName'].'"] )	{
> +							return window.opener.document.'.$this->P['formName'].'["'.$this->P['itemName'].'"];
> +						} else {
> +							close();
> +						}
> +					}
> +				';
> +			}
> +		} else {	// Functions used, if the link selector is in RTE or any other mode:
>  			$JScode.='
>  				function link_typo3Page(id,anchor)	{	//
>  					var theLink = \''.$this->siteURL.'?id=\'+id+(anchor?anchor:"");
> @@ -1127,6 +1138,7 @@
>  			break;
>  			case 'file':
>  			case 'filedrag':
> +			case 'folder':
>  				if (isset($this->expandFolder))	{
>  					$data['expandFolder']=$this->expandFolder;
>  					$store = true;
> @@ -1163,7 +1175,7 @@
>  		$content=$this->doc->startPage('RTE link');
>  
>  			// Initializing the action value, possibly removing blinded values etc:
> -		$allowedItems = array_diff(explode(',','page,file,url,mail,spec'),t3lib_div::trimExplode(',',$this->thisConfig['blindLinkOptions'],1));
> +		$allowedItems = array_diff(explode(',','page,file,folder,url,mail,spec'),t3lib_div::trimExplode(',',$this->thisConfig['blindLinkOptions'],1));
>  		$allowedItems = array_diff($allowedItems, t3lib_div::trimExplode(',',$this->P['params']['blindLinkOptions']));
>  
>  			//call hook for extra options
> @@ -1194,6 +1206,12 @@
>  			$menuDef['file']['url'] = '#';
>  			$menuDef['file']['addParams'] = 'onclick="jumpToUrl(\'?act=file\');return false;"';
>  		}
> +		if (in_array('folder',$allowedItems)){
> +			$menuDef['folder']['isActive'] = $this->act=='folder';
> +			$menuDef['folder']['label'] = $LANG->getLL('folder',1);
> +			$menuDef['folder']['url'] = '#';
> +			$menuDef['folder']['addParams'] = 'onclick="jumpToUrl(\'?act=folder\');return false;"';
> +		}
>  		if (in_array('url',$allowedItems)) {
>  			$menuDef['url']['isActive'] = $this->act=='url';
>  			$menuDef['url']['label'] = $LANG->getLL('extUrl',1);
> @@ -1261,11 +1279,12 @@
>  				$content.=$extUrl;
>  			break;
>  			case 'file':
> +			case 'folder':
>  				$foldertree = t3lib_div::makeInstance('rteFolderTree');
>  				$foldertree->thisScript = $this->thisScript;
>  				$tree=$foldertree->getBrowsableTree();
>  
> -				if (!$this->curUrlInfo['value'] || $this->curUrlInfo['act']!='file')	{
> +				if (!$this->curUrlInfo['value'] || $this->curUrlInfo['act']!=$this->act)	{
>  					$cmpPath='';
>  				} elseif (substr(trim($this->curUrlInfo['info']),-1)!='/')	{
>  					$cmpPath=PATH_site.dirname($this->curUrlInfo['info']).'/';
> @@ -1275,17 +1294,17 @@
>  				}
>  
>  				list(,,$specUid) = explode('_',$this->PM);
> -				$files = $this->expandFolder($foldertree->specUIDmap[$specUid], $this->P['params']['allowedExtensions']);
> +				$filesOrFolders = $this->expandFolder($foldertree->specUIDmap[$specUid], $this->P['params']['allowedExtensions']);
>  
>  				$content.= '
>  
>  			<!--
> -				Wrapper table for folder tree / file list:
> +				Wrapper table for folder tree / file list / folder list:
>  			-->
>  					<table border="0" cellpadding="0" cellspacing="0" id="typo3-linkFiles">
>  						<tr>
>  							<td class="c-wCell" valign="top">'.$this->barheader($GLOBALS['LANG']->getLL('folderTree').':').$tree.'</td>
> -							<td class="c-wCell" valign="top">'.$files.'</td>
> +							<td class="c-wCell" valign="top">'.$filesOrFolders.'</td>
>  						</tr>
>  					</table>
>  					';
> @@ -1608,14 +1627,74 @@
>  		return $content;
>  	}
>  
> +	/**
> +	 * TYPO3 Element Browser: Showing a folder tree, allowing you to browse for folders.
> +	 *
> +	 * @return	string		HTML content for the module
> +	 */
> +	function main_folder()	{
> +		global $BE_USER;
>  
> +			// Starting content:
> +		$content.=$this->doc->startPage('TBE folder selector');
> + 
> +			// Init variable:
> +		$pArr = explode('|',$this->bparams);
> + 
> +			// Create upload/create folder forms, if a path is given:
> +		$fileProcessor = t3lib_div::makeInstance('t3lib_basicFileFunctions');
> +		$fileProcessor->init($GLOBALS['FILEMOUNTS'], $GLOBALS['TYPO3_CONF_VARS']['BE']['fileExtensions']);
> +		$path=$this->expandFolder;
> +		if (!$path || !@is_dir($path))	{
> +			$path = $fileProcessor->findTempFolder().'/';	// The closest TEMP-path is found
> +		}
> +		if ($path!='/' && @is_dir($path))	{
> +			$createFolder=$this->createFolder($path);
> +		} else {
> +			$createFolder='';
> +		}
>  
> +			// Create folder tree:
> +		$foldertree = t3lib_div::makeInstance('TBE_FolderTree');
> +		$foldertree->thisScript=$this->thisScript;
> +		$foldertree->ext_noTempRecyclerDirs = ($this->mode == 'filedrag');
> +		$tree = $foldertree->getBrowsableTree(false);
>  
> +		list(,,$specUid) = explode('_',$this->PM);
> + 
> +		if ($this->mode=='filedrag')	{
> +			$folders = $this->TBE_dragNDrop($foldertree->specUIDmap[$specUid],$pArr[3]);
> +		} else {
> +			$folders = $this->TBE_expandSubFolders($foldertree->specUIDmap[$specUid]);
> +		}
>  
> +			// Putting the parts together, side by side:
> +		$content.= '
>  
> +			<!--
> +				Wrapper table for folder tree / folder list:
> +			-->
> +			<table border="0" cellpadding="0" cellspacing="0" id="typo3-EBfiles">
> +				<tr>
> +					<td class="c-wCell" valign="top">'.$this->barheader($GLOBALS['LANG']->getLL('folderTree').':').$tree.'</td>
> +					<td class="c-wCell" valign="top">'.$folders.'</td>
> +				</tr>
> +			</table>
> +			';
>  
> +			// Adding create folder if applicable:
> +		if ($BE_USER->isAdmin() || $BE_USER->getTSConfigVal('options.createFoldersInEB')) {
> +			$content.=$createFolder;
> +		}
>  
> +			// Add some space
> +		$content.='<br /><br />';
>  
> +			// Ending page, returning content:
> +		$content.= $this->doc->endPage();
> +		$content = $this->doc->insertStylesAndJS($content);
> +		return $content;
> +	}
>  
>  
>  
> @@ -1902,6 +1981,37 @@
>  	}
>  
>  	/**
> +	 * Render list of folders inside a folder.
> +	 *
> +	 * @param	string		string of the current folder
> +	 * @return	string		HTML output
> +	 */
> +	function TBE_expandSubFolders($expandFolder=0) {
> +		global $LANG;
> +
> +		$expandFolder = $expandFolder ? $expandFolder : $this->expandFolder;
> +		$out='';
> +		if ($expandFolder && $this->checkFolder($expandFolder))	{
> +			if (t3lib_div::isFirstPartOfStr($expandFolder,PATH_site)) {
> +				$rootFolder = substr($expandFolder, strlen(PATH_site));
> +			}
> +			$folders = array();
> +
> +				// Listing the folders:
> +			$folders = t3lib_div::get_dirs($expandFolder);
> +			if (count($folders) > 0) {
> +				foreach ($folders as $index => $folder) {
> +					$folders[$index] = $rootFolder.$folder.'/';
> +				}
> +			}
> +			$out.= $this->folderList($rootFolder, $folders);
> +		}
> +
> +			// Return accumulated content for folderlisting:
> +		return $out;
> +	}
> +
> +	/**
>  	 * Render list of files.
>  	 *
>  	 * @param	array		List of files. See t3lib_div::getFilesInDir
> @@ -2031,6 +2141,105 @@
>  	}
>  
>  	/**
> +	 * Render list of folders.
> +	 *
> +	 * @param	array		List of folders. See t3lib_div::get_dirs
> +	 * @param	string		If set a header with a folder icon and folder name are shown
> +	 * @return	string		HTML output
> +	 */
> +	function folderList($base_folder, $folders) {
> +		global $LANG, $BACK_PATH;
> +
> +		$out='';
> +
> +			// Create headline (showing number of folders):
> +		$out.=$this->barheader(sprintf($GLOBALS['LANG']->getLL('folders').' (%s):',count($folders)));
> +
> +		$titleLen=intval($GLOBALS['BE_USER']->uc['titleLen']);
> +
> +			// Create the header of current folder:
> +		if($base_folder) {
> +			if (strstr($base_folder,',') || strstr($base_folder,'|'))	{	// In case an invalid character is in the filepath, display error message:
> +				$eMsg = $LANG->JScharCode(sprintf($LANG->getLL('invalidChar'),', |'));
> +				$ATag = $ATag_alt = "<a href=\"#\" onclick=\"alert(".$eMsg.");return false;\">";
> +			} else {	// If foldername is OK, just add it:
> +				$ATag = "<a href=\"#\" onclick=\"return insertElement('','".rawurlencode($base_folder)."', 'folder', '".rawurlencode($base_folder)."', unescape('".rawurlencode($base_folder)."'), '".$fI['extension']."', '".$ficon."');\">";
> +				$ATag_alt = substr($ATag,0,-4).",'',1);\">";
> +			}
> +			$ATag_e='</a>';
> +
> +			$picon = $ATag_alt;
> +			$picon.='<img'.t3lib_iconWorks::skinImg($BACK_PATH,'gfx/i/_icon_webfolders.gif','width="18" height="16"').' alt="" />';
> +			$picon.=htmlspecialchars(t3lib_div::fixed_lgd_cs(basename($base_folder),$titleLen));
> +			$picon.=$ATag_e;
> +			$out.=$picon.'<br />';
> +		}
> +
> +			// Listing the folders:
> +		if (is_array($folders))	{
> +			if (count($folders) > 0) {
> +					// Traverse the folder list:
> +				$lines=array();
> +				foreach($folders as $folderpath)	{
> +					$fI=pathinfo($folderpath);
> +
> +						// Create folder icon:
> +					$icon = '<img src="clear.gif" width="16" height="16" alt="" /><img'.t3lib_iconWorks::skinImg($BACK_PATH,'gfx/i/_icon_webfolders.gif','width="16" height="16"').' title="'.htmlspecialchars($fI['basename'].$size).'" class="absmiddle" alt="" />';
> +
> +						// Create links for adding the folder:
> +					if ($this->P['itemName'] != '' && $this->P['formName'] != '') {
> +						$ATag = "<a href=\"#\" onclick=\"return set_folderpath(unescape('".rawurlencode($folderpath)."'));\">";
> +					} else {
> +						$ATag = "<a href=\"#\" onclick=\"return insertElement('','".rawurlencode($folderpath)."', 'folder', '".rawurlencode($folderpath)."', unescape('".rawurlencode($folderpath)."'), '".$fI['extension']."', '".$ficon."');\">";
> +					}
> +					if (strstr($folderpath,',') || strstr($folderpath,'|'))	{	// In case an invalid character is in the filepath, display error message:
> +						$eMsg = $LANG->JScharCode(sprintf($LANG->getLL('invalidChar'),', |'));
> +						$ATag = $ATag_alt = "<a href=\"#\" onclick=\"alert(".$eMsg.");return false;\">";
> +					} else {	// If foldername is OK, just add it:
> +						$ATag_alt = substr($ATag,0,-4).",'',1);\">";
> +					}
> +					$ATag_e='</a>';
> +
> +						// Combine icon and folderpath:
> +					$foldernameAndIcon=$ATag_alt.$icon.htmlspecialchars(t3lib_div::fixed_lgd_cs(basename($folderpath),$titleLen)).$ATag_e;
> +
> +					if ($this->P['itemName'] != '') {
> +						$lines[]='
> +							<tr class="bgColor4">
> +								<td nowrap="nowrap">'.$foldernameAndIcon.'&nbsp;</td>
> +								<td>&nbsp;</td>
> +							</tr>';
> +					} else {
> +						$lines[]='
> +							<tr class="bgColor4">
> +								<td nowrap="nowrap">'.$foldernameAndIcon.'&nbsp;</td>
> +								<td>'.$ATag.'<img'.t3lib_iconWorks::skinImg($BACK_PATH,'gfx/plusbullet2.gif','width="18" height="16"').' title="'.$LANG->getLL('addToList',1).'" alt="" />'.$ATag_e.'</td>
> +								<td>&nbsp;</td>
> +							</tr>';
> +					}
> +					$lines[]='
> +							<tr>
> +								<td colspan="3"><img src="clear.gif" width="1" height="3" alt="" /></td>
> +							</tr>';
> +				}
> +			}
> +
> +				// Wrap all the rows in table tags:
> +			$out.='
> +
> +		<!--
> +			Folder listing
> +		-->
> +				<table border="0" cellpadding="0" cellspacing="1" id="typo3-folderList">
> +					'.implode('',$lines).'
> +				</table>';
> +		}
> +
> +			// Return accumulated content for folderlisting:
> +		return $out;
> +	}
> +
> +	/**
>  	 * For RTE: This displays all IMAGES (gif,png,jpg) (from extensionList) from folder. Thumbnails are shown for images.
>  	 * This listing is of images located in the web-accessible paths ONLY - the listing is for drag-n-drop use in the RTE
>  	 *
> Index: typo3/browse_links.php
> ===================================================================
> --- typo3/browse_links.php	(revision 2950)
> +++ typo3/browse_links.php	(working copy)
> @@ -178,6 +178,7 @@
>  				break;
>  				case 'file':
>  				case 'filedrag':
> +				case 'folder':
>  						// Setting alternative browsing mounts (ONLY local to browse_links.php this script so they stay "read-only")
>  					$altMountPoints = trim($GLOBALS['BE_USER']->getTSConfigVal('options.folderTree.altElementBrowserMountPoints'));
>  					if ($altMountPoints)	{
> @@ -204,6 +205,9 @@
>  				case 'filedrag':
>  					$this->content = $this->browser->main_file();
>  				break;
> +				case 'folder':
> +					$this->content = $this->browser->main_folder();
> +				break;
>  				case 'wizard':
>  					$this->content = $this->browser->main_rte(1);
>  				break;


More information about the TYPO3-team-core mailing list