diff --git a/controllers/ItemsController.php b/controllers/ItemsController.php index d3a6e489..43c25974 100644 --- a/controllers/ItemsController.php +++ b/controllers/ItemsController.php @@ -424,6 +424,19 @@ public function items() { $this->permissions ); } + // Unfiled items + else if ($this->subset == 'unfiled') { + $this->allowMethods(['GET']); + + $title = "Unfiled items"; + $results = Zotero_Items::search( + $this->objectLibraryID, + true, + $this->queryParams, + $this->permissions, + true + ); + } else if ($this->subset == 'children') { $item = Zotero_Items::getByLibraryAndKey($this->objectLibraryID, $this->objectKey); if (!$item) { diff --git a/controllers/TagsController.php b/controllers/TagsController.php index dad6a482..6f5ed48d 100644 --- a/controllers/TagsController.php +++ b/controllers/TagsController.php @@ -72,7 +72,7 @@ public function tags() { $this->allowMethods(array('GET')); // Tags within items - if (($this->scopeObject == 'items' && !$this->scopeObjectKey) || $this->scopeObject == 'collection-items') { + if (($this->scopeObject == 'items' && (!$this->scopeObjectKey || $this->scopeObjectKey == 'unfiled')) || $this->scopeObject == 'collection-items') { // Proxy certain query parameters to items search $validItemParams = [ 'itemQ' => 'q', @@ -127,6 +127,17 @@ public function tags() { $this->permissions ); } + // Unfiled + else if($this->scopeObjectKey == 'unfiled') { + $title = "Unfiled tags"; + $itemResults = Zotero_Items::search( + $this->objectLibraryID, + true, + $itemParams, + $this->permissions, + true + ); + } else { $itemResults = Zotero_Items::search( $this->objectLibraryID, diff --git a/include/config/routes.inc.php b/include/config/routes.inc.php index b8b1a75d..8d44fd4c 100644 --- a/include/config/routes.inc.php +++ b/include/config/routes.inc.php @@ -107,6 +107,10 @@ $router->map('/users/i:objectUserID/publications/items/:objectKey/children', ['controller' => 'Items', 'extra' => ['publications' => true, 'subset' => 'children']]); $router->map('/users/i:objectUserID/publications/items/:objectKey', ['controller' => 'Items', 'extra' => ['publications' => true]]); +// Unfiled items +$router->map('/users/i:objectUserID/items/unfiled',['controller' => 'Items', 'extra' => ['subset' => 'unfiled']]); +$router->map('/users/i:objectUserID/items/unfiled/tags', ['controller' => 'Tags', 'extra' => ['subset' => 'unfiled']]); + // Other top-level URLs, with an optional key and subset $router->map('/users/i:objectUserID/:controller/:objectKey/:subset'); $router->map('/groups/i:objectGroupID/:controller/:objectKey/:subset'); diff --git a/model/Items.inc.php b/model/Items.inc.php index df08d0c6..6cbe290a 100644 --- a/model/Items.inc.php +++ b/model/Items.inc.php @@ -65,7 +65,7 @@ public static function getDeleted($libraryID, $asIDs) { } - public static function search($libraryID, $onlyTopLevel = false, array $params = [], Zotero_Permissions $permissions = null) { + public static function search($libraryID, $onlyTopLevel = false, array $params = [], Zotero_Permissions $permissions = null, $unfiled = false ) { $rnd = "_" . uniqid($libraryID . "_"); $results = array('results' => array(), 'total' => 0); @@ -154,6 +154,10 @@ public static function search($libraryID, $onlyTopLevel = false, array $params = && ($params['format'] == 'keys' || $params['format'] == 'versions' || $topLevelItemSort)) { $sql .= "LEFT JOIN items ITLI ON (ITLI.itemID=$itemIDSelector) "; } + + if ($unfiled) { + $sql .= "LEFT JOIN collectionItems CI ON (CI.itemID=I.itemID) "; + } } // For 'q' we need the note; for sorting by title, we need the note title @@ -490,6 +494,10 @@ public static function search($libraryID, $onlyTopLevel = false, array $params = if ($skipITLI) { $sql .= "AND ITL.itemID IS NULL "; } + + if ($unfiled) { + $sql .= "AND CI.collectionID IS NULL "; + } $sql .= "ORDER BY "; @@ -2574,7 +2582,7 @@ private static function loadItems($libraryID, $itemIDs=array()) { } } } - + public static function getSortTitle($title) { if (!$title) {