diff --git a/apps/files/appinfo/app.php b/apps/files/appinfo/app.php index 43e6cffa33..9af36c682f 100644 --- a/apps/files/appinfo/app.php +++ b/apps/files/appinfo/app.php @@ -10,7 +10,7 @@ OCP\App::addNavigationEntry(array("id" => "files_index", "icon" => OCP\Util::imagePath("core", "places/files.svg"), "name" => $l->t("Files"))); -OC_Search::registerProvider('OC_Search_Provider_File'); +\OC::$server->getSearch()->registerProvider('OC\Search\Provider\File'); $templateManager = OC_Helper::getFileTemplateManager(); $templateManager->registerTemplate('text/html', 'core/templates/filetemplates/template.html'); diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 8d871d6dac..df0c40a440 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -284,7 +284,7 @@ $('#webdavurl').select(); }); - //scroll to and highlight preselected file + //FIXME scroll to and highlight preselected file /* if (getURLParameter('scrollto')) { FileList.scrollTo(getURLParameter('scrollto')); diff --git a/core/js/js.js b/core/js/js.js index d02dc6445f..c0e5324a8d 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -585,6 +585,13 @@ OC.search.customResults={}; OC.search.currentResult=-1; OC.search.lastQuery=''; OC.search.lastResults={}; +//translations for result type ids, can be extended by apps +OC.search.resultTypes={ + file: t('core','File'), + folder: t('core','Folder'), + image: t('core','Image'), + audio: t('core','Audio') +}; OC.addStyle.loaded=[]; OC.addScript.loaded=[]; diff --git a/lib/private/legacy/search.php b/lib/private/legacy/search.php new file mode 100644 index 0000000000..f77b43be2e --- /dev/null +++ b/lib/private/legacy/search.php @@ -0,0 +1,68 @@ +. + * + */ + +/** + * provides an interface to all search providers + * @deprecated see lib/search.php + */ +class OC_Search { + /** + * @return \OCP\ISearch + */ + private static function getSearch() { + return \OC::$server->getSearch(); + } + + /** + * Search all providers for $query + * @param string $query + * @return array An array of OCP\Search\Result's + */ + public static function search($query) { + return self::getSearch()->search($query); + } + + /** + * Register a new search provider to search with + * @param string $class class name of a OCP\Search\Provider + * @param array $options optional + */ + public static function registerProvider($class, $options = array()) { + return self::getSearch()->registerProvider($class, $options); + } + + /** + * Remove one existing search provider + * @param string $provider class name of a OCP\Search\Provider + */ + public static function removeProvider($provider) { + return self::getSearch()->removeProvider($provider); + } + + /** + * Remove all registered search providers + */ + public static function clearProviders() { + return self::getSearch()->clearProviders(); + } + +} diff --git a/lib/private/legacy/search/provider.php b/lib/private/legacy/search/provider.php new file mode 100644 index 0000000000..d200c988c4 --- /dev/null +++ b/lib/private/legacy/search/provider.php @@ -0,0 +1,22 @@ +. + * + */ + +abstract class OC_Search_Provider extends \OCP\Search\Provider { + +} diff --git a/lib/private/legacy/search/provider/file.php b/lib/private/legacy/search/provider/file.php new file mode 100644 index 0000000000..e610281131 --- /dev/null +++ b/lib/private/legacy/search/provider/file.php @@ -0,0 +1,22 @@ +. + * + */ + +class OC_Search_Provider_File extends \OC\Search\Provider\File { + +} diff --git a/lib/private/legacy/search/result.php b/lib/private/legacy/search/result.php new file mode 100644 index 0000000000..f3e6ecbb99 --- /dev/null +++ b/lib/private/legacy/search/result.php @@ -0,0 +1,35 @@ +. + * + */ + +class OC_Search_Result extends \OCP\Search\Result { + + /** + * Create a new search result + * @param string $id unique identifier from application: '[app_name]/[item_identifier_in_app]' + * @param string $name displayed text of result + * @param string $link URL to the result within its app + * @param string $type @deprecated because it is now set in \OC\Search\Result descendants + */ + public function __construct($id = null, $name = null, $link = null, $type = null) { + $this->id = $id; + $this->name = $name; + $this->link = $link; + $this->type = $type; + } +} diff --git a/lib/private/search.php b/lib/private/search.php index 3f540090fd..bcaebdddd9 100644 --- a/lib/private/search.php +++ b/lib/private/search.php @@ -20,70 +20,77 @@ * */ +namespace OC; +use OCP\Search\Provider; +use OCP\ISearch; /** - * provides an interface to all search providers + * Provide an interface to all search providers */ -class OC_Search{ - static private $providers=array(); - static private $registeredProviders=array(); +class Search implements ISearch { + + private $providers = array(); + private $registeredProviders = array(); /** - * remove all registered search providers - */ - public static function clearProviders() { - self::$providers=array(); - self::$registeredProviders=array(); - } - - /** - * register a new search provider to be used - */ - public static function registerProvider($class, $options=array()) { - self::$registeredProviders[]=array('class'=>$class, 'options'=>$options); - } - - /** - * search all provider for $query + * Search all providers for $query * @param string $query - * @return array An array of OC_Search_Result's + * @return array An array of OC\Search\Result's */ - public static function search($query) { - self::initProviders(); - $results=array(); - foreach(self::$providers as $provider) { - $results=array_merge($results, $provider->search($query)); + public function search($query) { + $this->initProviders(); + $results = array(); + foreach($this->providers as $provider) { + /** @var $provider Provider */ + $results = array_merge($results, $provider->search($query)); } return $results; } /** - * remove an existing search provider - * @param string $provider class name of a OC_Search_Provider + * Remove all registered search providers */ - public static function removeProvider($provider) { - self::$registeredProviders = array_filter( - self::$registeredProviders, - function ($element) use ($provider) { - return ($element['class'] != $provider); - } - ); - // force regeneration of providers on next search - self::$providers=array(); + public function clearProviders() { + $this->providers=array(); + $this->registeredProviders=array(); } - /** - * create instances of all the registered search providers + * Remove one existing search provider + * @param string $provider class name of a OC\Search\Provider */ - private static function initProviders() { - if(count(self::$providers)>0) { + public function removeProvider($provider) { + $this->registeredProviders = array_filter( + $this->registeredProviders, + function ($element) use ($provider) { + return ($element['class'] != $provider); + } + ); + // force regeneration of providers on next search + $this->providers=array(); + } + + /** + * Register a new search provider to search with + * @param string $class class name of a OC\Search\Provider + * @param array $options optional + */ + public function registerProvider($class, $options=array()) { + $this->registeredProviders[]=array('class'=>$class, 'options'=>$options); + } + + /** + * Create instances of all the registered search providers + */ + private function initProviders() { + if(count($this->providers)>0) { return; } - foreach(self::$registeredProviders as $provider) { - $class=$provider['class']; - $options=$provider['options']; - self::$providers[]=new $class($options); + foreach($this->registeredProviders as $provider) { + $class = $provider['class']; + $options = $provider['options']; + $this->providers[]=new $class($options); } } + } diff --git a/lib/private/search/provider.php b/lib/private/search/provider.php deleted file mode 100644 index b617b9c5d9..0000000000 --- a/lib/private/search/provider.php +++ /dev/null @@ -1,18 +0,0 @@ -options=$options; - } - - /** - * search for $query - * @param string $query - * @return array An array of OC_Search_Result's - */ - abstract public function search($query); -} diff --git a/lib/private/search/provider/file.php b/lib/private/search/provider/file.php index 9bd5093151..cbd3a25373 100644 --- a/lib/private/search/provider/file.php +++ b/lib/private/search/provider/file.php @@ -1,46 +1,69 @@ . + * + */ -class OC_Search_Provider_File extends OC_Search_Provider{ +namespace OC\Search\Provider; +use OC\Files\Filesystem; + +/** + * Provide search results from the 'files' app + */ +class File extends \OCP\Search\Provider { + + /** + * Search for files and folders matching the given query + * @param string $query + * @return \OCP\Search\Result + */ function search($query) { - $files=\OC\Files\Filesystem::search($query, true); - $results=array(); - $l=OC_L10N::get('lib'); - foreach($files as $fileData) { - $path = $fileData['path']; - $mime = $fileData['mimetype']; - - $name = basename($path); - $container = dirname($path); - $text = ''; - $skip = false; - if($mime=='httpd/unix-directory') { - $link = OC_Helper::linkTo( 'files', 'index.php', array('dir' => $path)); - $type = (string)$l->t('Files'); - }else{ - $link = OC_Helper::linkToRoute( 'download', array('file' => $path)); - $mimeBase = $fileData['mimepart']; - switch($mimeBase) { - case 'audio': - $skip = true; - break; - case 'text': - $type = (string)$l->t('Text'); - break; - case 'image': - $type = (string)$l->t('Images'); - break; - default: - if($mime=='application/xml') { - $type = (string)$l->t('Text'); - }else{ - $type = (string)$l->t('Files'); - } - } + $files = Filesystem::search($query); + $results = array(); + // edit results + foreach ($files as $fileData) { + // skip versions + if (strpos($fileData['path'], '_versions') === 0) { + continue; } - if(!$skip) { - $results[] = new OC_Search_Result($name, $text, $link, $type, $container); + // skip top-level folder + if ($fileData['name'] === 'files' && $fileData['parent'] === -1) { + continue; } + // create audio result + if($fileData['mimepart'] === 'audio'){ + $result = new \OC\Search\Result\Audio($fileData); + } + // create image result + elseif($fileData['mimepart'] === 'image'){ + $result = new \OC\Search\Result\Image($fileData); + } + // create folder result + elseif($fileData['mimetype'] === 'httpd/unix-directory'){ + $result = new \OC\Search\Result\Folder($fileData); + } + // or create file result + else{ + $result = new \OC\Search\Result\File($fileData); + } + // add to results + $results[] = $result; } + // return return $results; } + } diff --git a/lib/private/search/result.php b/lib/private/search/result.php deleted file mode 100644 index ceefeab2da..0000000000 --- a/lib/private/search/result.php +++ /dev/null @@ -1,27 +0,0 @@ -name=$name; - $this->text=$text; - $this->link=$link; - $this->type=$type; - $this->container=$container; - } -} diff --git a/lib/private/search/result/audio.php b/lib/private/search/result/audio.php new file mode 100644 index 0000000000..3adbb40056 --- /dev/null +++ b/lib/private/search/result/audio.php @@ -0,0 +1,36 @@ +. + * + */ + +namespace OC\Search\Result; + +/** + * A found audio file + */ +class Audio extends File { + + /** + * Type name; translated in templates + * @var string + */ + public $type = 'audio'; + + /** + * @TODO add ID3 information + */ +} diff --git a/lib/private/search/result/file.php b/lib/private/search/result/file.php new file mode 100644 index 0000000000..da5fa64ef4 --- /dev/null +++ b/lib/private/search/result/file.php @@ -0,0 +1,111 @@ +. + * + */ + +namespace OC\Search\Result; +use \OC\Files\Filesystem; +/** + * A found file + */ +class File extends \OCP\Search\Result { + + /** + * Type name; translated in templates + * @var string + */ + public $type = 'file'; + + /** + * Path to file + * @var string + */ + public $path; + + /** + * Size, in bytes + * @var int + */ + public $size; + + /** + * Date modified, in human readable form + * @var string + */ + public $modified; + + /** + * File mime type + * @var string + */ + public $mime_type; + + /** + * File permissions: + * + * @var string + */ + public $permissions; + + /** + * Create a new file search result + * @param array $data file data given by provider + */ + public function __construct(array $data = null) { + $info = pathinfo($data['path']); + $this->id = $data['fileid']; + $this->name = $info['basename']; + $this->link = \OCP\Util::linkTo( + 'files', + 'index.php', + array('dir' => $info['dirname'], 'file' => $info['basename']) + ); + $this->permissions = self::get_permissions($data['path']); + $this->path = (strpos($data['path'], 'files') === 0) ? substr($data['path'], 5) : $data['path']; + $this->size = $data['size']; + $this->modified = $data['mtime']; + $this->mime_type = $data['mimetype']; + } + + /** + * Determine permissions for a given file path + * @param string $path + * @return int + */ + function get_permissions($path) { + // add read permissions + $permissions = \OCP\PERMISSION_READ; + // get directory + $fileinfo = pathinfo($path); + $dir = $fileinfo['dirname'] . '/'; + // add update permissions + if (Filesystem::isUpdatable($dir)) { + $permissions |= \OCP\PERMISSION_UPDATE; + } + // add delete permissions + if (Filesystem::isDeletable($dir)) { + $permissions |= \OCP\PERMISSION_DELETE; + } + // add share permissions + if (Filesystem::isSharable($dir)) { + $permissions |= \OCP\PERMISSION_SHARE; + } + // return + return $permissions; + } + +} diff --git a/lib/private/search/result/folder.php b/lib/private/search/result/folder.php new file mode 100644 index 0000000000..29469a1d11 --- /dev/null +++ b/lib/private/search/result/folder.php @@ -0,0 +1,33 @@ +. + * + */ + +namespace OC\Search\Result; + +/** + * A found folder + */ +class Folder extends File { + + /** + * Type name; translated in templates + * @var string + */ + public $type = 'folder'; + +} diff --git a/lib/private/search/result/image.php b/lib/private/search/result/image.php new file mode 100644 index 0000000000..f4e6be56c8 --- /dev/null +++ b/lib/private/search/result/image.php @@ -0,0 +1,36 @@ +. + * + */ + +namespace OC\Search\Result; + +/** + * A found image file + */ +class Image extends File { + + /** + * Type name; translated in templates + * @var string + */ + public $type = 'image'; + + /** + * @TODO add EXIF information + */ +} diff --git a/lib/private/server.php b/lib/private/server.php index 47bdee4b0f..da70586307 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -186,6 +186,9 @@ class Server extends SimpleContainer implements IServerContainer { } return $router; }); + $this->registerService('Search', function($c){ + return new Search(); + }); $this->registerService('Db', function($c){ return new Db(); }); @@ -422,6 +425,13 @@ class Server extends SimpleContainer implements IServerContainer { return $this->query('Router'); } + /** + * Returns a search instance + * @return \OCP\ISearch + */ + function getSearch() { + return $this->query('Search'); + } /** * Returns an instance of the db facade diff --git a/lib/public/isearch.php b/lib/public/isearch.php new file mode 100644 index 0000000000..3b83dbf35e --- /dev/null +++ b/lib/public/isearch.php @@ -0,0 +1,57 @@ +. + * + */ + +namespace OCP; + + +/** + * Small Interface for Search + */ +interface ISearch { + + /** + * Search all providers for $query + * @param string $query + * @return array An array of OCP\Search\Result's + */ + public function search($query); + + /** + * Register a new search provider to search with + * @param string $class class name of a OCP\Search\Provider + * @param array $options optional + */ + public function registerProvider($class, $options = array()); + + /** + * Remove one existing search provider + * @param string $provider class name of a OCP\Search\Provider + */ + public function removeProvider($provider); + + /** + * Remove all registered search providers + */ + public function clearProviders(); + +} diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 22176c36b8..8bf9782858 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -204,4 +204,12 @@ interface IServerContainer { * @return \OCP\Route\IRouter */ function getRouter(); + + /** + * Returns a search instance + * + * @return \OCP\ISearch + */ + function getSearch(); + } diff --git a/lib/public/search/provider.php b/lib/public/search/provider.php new file mode 100644 index 0000000000..0506f091dd --- /dev/null +++ b/lib/public/search/provider.php @@ -0,0 +1,47 @@ +. + * + */ + +namespace OCP\Search; + +/** + * Provides a template for search functionality throughout ownCloud; + */ +abstract class Provider { + + /** + * List of options (currently unused) + * @var array + */ + private $options; + + /** + * Constructor + * @param array $options + */ + public function __construct($options) { + $this->options = $options; + } + + /** + * Search for $query + * @param string $query + * @return array An array of OCP\Search\Result's + */ + abstract public function search($query); +} diff --git a/lib/public/search/result.php b/lib/public/search/result.php new file mode 100644 index 0000000000..c70f1bde88 --- /dev/null +++ b/lib/public/search/result.php @@ -0,0 +1,65 @@ +. + * + */ + +namespace OCP\Search; + +/** + * The generic result of a search + */ +class Result { + + /** + * A unique identifier for the result, usually given as the item ID in its + * corresponding application. + * @var string + */ + public $id; + + /** + * The name of the item returned; this will be displayed in the search + * results. + * @var string + */ + public $name; + + /** + * URL to the application item. + * @var string + */ + public $link; + + /** + * The type of search result returned; for consistency, name this the same + * as the class name (e.g. \OC\Search\File -> 'file') in lowercase. + * @var string + */ + public $type = 'generic'; + + /** + * Create a new search result + * @param string $id unique identifier from application: '[app_name]/[item_identifier_in_app]' + * @param string $name displayed text of result + * @param string $link URL to the result within its app + */ + public function __construct($id = null, $name = null, $link = null) { + $this->id = $id; + $this->name = $name; + $this->link = $link; + } +} diff --git a/search/ajax/search.php b/search/ajax/search.php index 0cc1f9d30c..546fccc644 100644 --- a/search/ajax/search.php +++ b/search/ajax/search.php @@ -26,7 +26,7 @@ OC_JSON::checkLoggedIn(); $query=(isset($_GET['query']))?$_GET['query']:''; if($query) { - $result=OC_Search::search($query); + $result = \OC::$server->getSearch()->search($query); OC_JSON::encodedPrint($result); } else { diff --git a/search/js/result.js b/search/js/result.js index 780f513edc..04e999c62e 100644 --- a/search/js/result.js +++ b/search/js/result.js @@ -57,22 +57,27 @@ OC.search.showResults=function(results){ var row=$('#searchresults tr.template').clone(); row.removeClass('template'); row.addClass('result'); + row.data('type', typeid); row.data('name', type[i].name); row.data('text', type[i].text); - row.data('container', type[i].container); + row.data('index',index); + if (i === 0){ - row.children('td.type').text(typeid); + var typeName = OC.search.resultTypes[typeid]; + row.children('td.type').text(t('lib', typeName)); } row.find('td.result div.name').text(type[i].name); row.find('td.result div.text').text(type[i].text); - if (type[i].container) { - var containerName = OC.basename(type[i].container); + + if (type[i].path) { + var parent = OC.dirname(type[i].path); + var containerName = OC.basename(parent); if (containerName === '') { containerName = '/'; } var containerLink = OC.linkTo('files', 'index.php') - +'?dir='+encodeURIComponent(type[i].container) + +'?dir='+encodeURIComponent(parent) +'&scrollto='+encodeURIComponent(type[i].name); row.find('td.result a') .attr('href', containerLink) @@ -80,10 +85,16 @@ OC.search.showResults=function(results){ } else { row.find('td.result a').attr('href', type[i].link); } - row.data('index',index); + index++; - if(OC.search.customResults[typeid]){//give plugins the ability to customize the entries in here - OC.search.customResults[typeid](row,type[i]); + /** + * Give plugins the ability to customize the search results. For example: + * OC.search.customResults.file = function (row, item){ + * if(item.name.search('.json') >= 0) ... + * }; + */ + if(OC.search.customResults[typeid]){ + OC.search.customResults[typeid](row, type[i]); } $('#searchresults tbody').append(row); } @@ -104,4 +115,4 @@ OC.search.renderCurrent=function(){ $('#searchresults tr.result').removeClass('current'); $(result).addClass('current'); } -}; +}; \ No newline at end of file