mirror of
https://github.com/processwire/processwire.git
synced 2025-08-25 23:56:41 +02:00
Add support for Lister user-specific bookmarks. This enables users to create their own private or shared bookmarks in Lister.
This commit is contained in:
763
wire/modules/Process/ProcessPageLister/ListerBookmarks.php
Normal file
763
wire/modules/Process/ProcessPageLister/ListerBookmarks.php
Normal file
@@ -0,0 +1,763 @@
|
||||
<?php namespace ProcessWire;
|
||||
|
||||
class ListerBookmarks extends Wire {
|
||||
|
||||
/**
|
||||
* Indicates public bookmark stored in module settings
|
||||
*
|
||||
*/
|
||||
const typePublic = 0;
|
||||
|
||||
/**
|
||||
* Indicates user-owned bookmark stored in user meta data
|
||||
*
|
||||
*/
|
||||
const typeOwned = 1;
|
||||
|
||||
/**
|
||||
* @var ProcessPageLister
|
||||
*
|
||||
*/
|
||||
protected $lister;
|
||||
|
||||
/**
|
||||
* Cached user settings, becomes array once loaded
|
||||
*
|
||||
* @var null|array
|
||||
*
|
||||
*/
|
||||
protected $userSettings = null;
|
||||
|
||||
/**
|
||||
* User ID associated with above user settings (just in case it changes)
|
||||
*
|
||||
* @var int
|
||||
*
|
||||
*/
|
||||
protected $userSettingsID = 0;
|
||||
|
||||
/**
|
||||
* Module config settings, becomes array once loaded
|
||||
*
|
||||
* @var null|array
|
||||
*
|
||||
*/
|
||||
protected $moduleConfig = null;
|
||||
|
||||
/**
|
||||
* Page that Lister bookmarks are for
|
||||
*
|
||||
* @var Page|null
|
||||
*
|
||||
*/
|
||||
protected $page;
|
||||
|
||||
/**
|
||||
* User that Lister bookmarks are for
|
||||
*
|
||||
* @var User|null
|
||||
*
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
public function __construct(Page $page, User $user) {
|
||||
$this->page = $page;
|
||||
$this->user = $user;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Lister page that bookmarks will be for
|
||||
*
|
||||
* @param Page $page
|
||||
*
|
||||
*/
|
||||
public function setPage(Page $page) {
|
||||
$this->page = $page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user that bookmarks will be for
|
||||
*
|
||||
* @param User $user
|
||||
*
|
||||
*/
|
||||
public function setUser(User $user) {
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get owned bookmarks
|
||||
*
|
||||
* @param int $userID
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
public function getOwnedBookmarks($userID = 0) {
|
||||
|
||||
$settings = $this->getUserSettings($userID);
|
||||
$bookmarks = array();
|
||||
|
||||
if(!isset($settings['bookmarks'])) $settings['bookmarks'] = array();
|
||||
|
||||
foreach($settings['bookmarks'] as $bookmarkID => $bookmark) {
|
||||
if(empty($bookmarkID) || empty($bookmark['title'])) continue;
|
||||
$bookmarkID = $this->bookmarkStrID($bookmarkID, self::typeOwned);
|
||||
$bookmark = $this->wakeupBookmark($bookmark, $bookmarkID, self::typeOwned);
|
||||
if(!$bookmark) continue;
|
||||
if($userID && !$userID != $this->user->id && empty($bookmark['share'])) continue;
|
||||
$bookmarks[$bookmarkID] = $bookmark;
|
||||
}
|
||||
|
||||
return $bookmarks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save owned bookmarks
|
||||
*
|
||||
* @param array $bookmarks
|
||||
*
|
||||
*/
|
||||
public function saveOwnedBookmarks(array $bookmarks) {
|
||||
|
||||
$settings = $this->getUserSettings();
|
||||
$saveBookmarks = array();
|
||||
|
||||
if(!isset($settings['bookmarks'])) $settings['bookmarks'] = array();
|
||||
|
||||
// prep for save
|
||||
foreach($bookmarks as $bookmarkID => $bookmark) {
|
||||
if(empty($bookmark['title'])) continue;
|
||||
$bookmark = $this->sleepBookmark($bookmark);
|
||||
$bookmarkID = $this->bookmarkStrID($bookmarkID, self::typeOwned);
|
||||
$saveBookmarks[$bookmarkID] = $bookmark;
|
||||
}
|
||||
|
||||
$bookmarks = $saveBookmarks;
|
||||
|
||||
if($settings['bookmarks'] !== $bookmarks) {
|
||||
$settings['bookmarks'] = $bookmarks;
|
||||
if(empty($bookmarks)) unset($settings['bookmarks']);
|
||||
$this->message('Updated owned bookmarks', Notice::debug);
|
||||
$this->saveUserSettings($settings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user’s lister settings for current page
|
||||
*
|
||||
* @param int $userID
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
public function getUserSettings($userID = 0) {
|
||||
|
||||
$pageKey = $this->strID($this->page->id);
|
||||
$userSettings = array();
|
||||
|
||||
if($userID === $this->user->id) $userID = 0;
|
||||
|
||||
if($userID) {
|
||||
// other user
|
||||
$user = $this->wire('users')->get((int) $userID);
|
||||
if($user && $user->id) {
|
||||
$userSettings = $user->meta('lister');
|
||||
if(!is_array($userSettings)) $userSettings = array();
|
||||
}
|
||||
} else if($this->userSettings !== null && $this->user->id === $this->userSettingsID) {
|
||||
$userSettings = $this->userSettings;
|
||||
} else {
|
||||
$userSettings = $this->user->meta('lister');
|
||||
if(!is_array($userSettings)) $userSettings = array();
|
||||
$this->userSettings = $userSettings;
|
||||
$this->userSettingsID = $this->user->id;
|
||||
}
|
||||
|
||||
if(!isset($userSettings[$pageKey])) {
|
||||
$userSettings[$pageKey] = array();
|
||||
if(!$userID) $this->userSettings = $userSettings;
|
||||
}
|
||||
|
||||
return $userSettings[$pageKey];
|
||||
}
|
||||
|
||||
/**
|
||||
* Save user settings for current page
|
||||
*
|
||||
* @param array $settings
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function saveUserSettings(array $settings) {
|
||||
|
||||
$pageKey = $this->strID($this->page->id);
|
||||
$userSettings = $this->getUserSettings();
|
||||
$userSettings[$pageKey] = $settings;
|
||||
|
||||
foreach($userSettings as $key => $value) {
|
||||
|
||||
if(!$this->isID($key)) continue; // not a pageKey setting
|
||||
|
||||
// remove empty keys and settings
|
||||
if(is_array($value)) {
|
||||
foreach($value as $k => $v) {
|
||||
if(empty($v)) unset($value[$k]); // i.e. an empty $value['bookmarks']
|
||||
}
|
||||
}
|
||||
|
||||
$userSettings[$key] = $value;
|
||||
if(!$this->isValidPageKey($key)) $value = array(); // maintenance
|
||||
if(empty($value)) unset($userSettings[$key]);
|
||||
}
|
||||
|
||||
// if no changes, exit now
|
||||
if($userSettings === $this->userSettings) return false;
|
||||
|
||||
// save user settings
|
||||
$this->user->meta('lister', $userSettings);
|
||||
$this->userSettings = $userSettings;
|
||||
$this->message('Updated user settings', Notice::debug);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get public bookmarks (from module config)
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
public function getPublicBookmarks() {
|
||||
|
||||
$pageKey = $this->strID($this->page->id);
|
||||
$moduleConfig = $this->getModuleConfig();
|
||||
$bookmarks = array();
|
||||
|
||||
if(!isset($moduleConfig['bookmarks'][$pageKey])) {
|
||||
$moduleConfig['bookmarks'][$pageKey] = array();
|
||||
}
|
||||
|
||||
foreach($moduleConfig['bookmarks'][$pageKey] as $bookmarkID => $bookmark) {
|
||||
if(empty($bookmarkID) || empty($bookmark['title'])) continue;
|
||||
$bookmarkID = $this->bookmarkStrID($bookmarkID, self::typePublic);
|
||||
$bookmark = $this->wakeupBookmark($bookmark, $bookmarkID, self::typePublic);
|
||||
if($bookmark) $bookmarks[$bookmarkID] = $bookmark;
|
||||
}
|
||||
|
||||
$moduleConfig['bookmarks'][$pageKey] = $bookmarks;
|
||||
$this->setModuleConfig($moduleConfig);
|
||||
|
||||
return $bookmarks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save public bookmarks (to module config)
|
||||
*
|
||||
* @param array $bookmarks
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function savePublicBookmarks(array $bookmarks) {
|
||||
|
||||
$pageKey = $this->strID($this->page->id);
|
||||
$moduleConfig = $this->getModuleConfig();
|
||||
$saveBookmarks = array();
|
||||
|
||||
if(isset($moduleConfig['bookmarks'][$pageKey])) {
|
||||
// if given bookmarks are identical to what is in module config, there are no changes to save
|
||||
if($bookmarks === $moduleConfig['bookmarks'][$pageKey]) return false;
|
||||
}
|
||||
|
||||
// prep bookmarks for save
|
||||
foreach($bookmarks as $bookmarkID => $bookmark) {
|
||||
|
||||
// don't save bookmarks that lack a title or of the wrong type
|
||||
if(empty($bookmark['title'])) continue;
|
||||
if($bookmark['type'] != self::typePublic) continue;
|
||||
|
||||
// assign IDs for any bookmarks that don't have them
|
||||
if(empty($bookmarkID)) {
|
||||
$bookmarkID = time();
|
||||
while(isset($bookmarks["_$bookmarkID"])) $bookmarkID++;
|
||||
}
|
||||
|
||||
$bookmarkID = $this->bookmarkStrID($bookmarkID, self::typePublic);
|
||||
$saveBookmarks[$bookmarkID] = $this->sleepBookmark($bookmark);
|
||||
}
|
||||
|
||||
$bookmarks = $saveBookmarks;
|
||||
|
||||
if(empty($bookmarks)) {
|
||||
// remove if empty...
|
||||
unset($moduleConfig['bookmarks'][$pageKey]);
|
||||
} else {
|
||||
// ...otherwise populate
|
||||
$moduleConfig['bookmarks'][$pageKey] = $bookmarks;
|
||||
}
|
||||
|
||||
// check if any bookmarks in module config are for pages that no longer exist
|
||||
foreach($moduleConfig['bookmarks'] as $key => $bookmarks) {
|
||||
if(!$this->isValidPageKey($key)) {
|
||||
$this->warning("Removed expired bookmark for page $key", Notice::debug);
|
||||
unset($moduleConfig['bookmarks'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// if there are changes, save them
|
||||
return $this->saveModuleConfig($moduleConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save all bookmarks (whether public or owned)
|
||||
*
|
||||
* @param array $allBookmarks
|
||||
*
|
||||
*/
|
||||
public function saveBookmarks(array $allBookmarks) {
|
||||
|
||||
// save owned (user) bookmarks
|
||||
$ownedBookmarks = $this->filterBookmarksByType($allBookmarks, self::typeOwned);
|
||||
$this->saveOwnedBookmarks($ownedBookmarks);
|
||||
|
||||
if($this->user->isSuperuser()) {
|
||||
$publicBookmarks = $this->filterBookmarksByType($allBookmarks, self::typePublic);
|
||||
$this->savePublicBookmarks($publicBookmarks);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all bookmarks (public and owned)
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
public function getAllBookmarks() {
|
||||
$publicBookmarks = $this->getPublicBookmarks();
|
||||
$ownedBookmarks = $this->getOwnedBookmarks();
|
||||
$allBookmarks = array_merge($publicBookmarks, $ownedBookmarks);
|
||||
return $allBookmarks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get configured bookmarks allowed for current user, indexed by bookmark ID (int)
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
public function getBookmarks() {
|
||||
$bookmarks = array();
|
||||
foreach($this->getAllBookmarks() as $bookmarkID => $bookmark) {
|
||||
if(!$this->isBookmarkViewable($bookmark)) continue;
|
||||
$bookmarks[$bookmarkID] = $bookmark;
|
||||
}
|
||||
return $bookmarks;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a bookmark by ID (whether public or owned)
|
||||
*
|
||||
* @param string|int $bookmarkID
|
||||
* @param int|null $type
|
||||
* @return array|null
|
||||
*
|
||||
*/
|
||||
public function getBookmark($bookmarkID, $type = null) {
|
||||
if($type === null && strpos($bookmarkID, $this->typePrefix(self::typeOwned)) !== false) {
|
||||
$type = self::typeOwned;
|
||||
}
|
||||
if($type === self::typeOwned) {
|
||||
$prefix = $this->typePrefix(self::typeOwned);
|
||||
if(strpos($bookmarkID, $prefix) > 0) {
|
||||
// 123O456 where 123 is user ID and 456 is bookmark ID
|
||||
list($userID, $bookmarkID) = explode($prefix, $bookmarkID);
|
||||
$userID = (int) $userID;
|
||||
if($userID === $this->user->id) $userID = 0;
|
||||
$bookmarkID = $prefix . ((int) $bookmarkID);
|
||||
} else {
|
||||
$bookmarkID = $this->_bookmarkID($bookmarkID);
|
||||
$userID = 0;
|
||||
}
|
||||
$bookmarks = $this->getOwnedBookmarks($userID);
|
||||
$bookmarkID = $this->bookmarkStrID($bookmarkID, self::typeOwned);
|
||||
|
||||
} else {
|
||||
$bookmarks = $this->getPublicBookmarks();
|
||||
$bookmarkID = $this->bookmarkStrID($bookmarkID, self::typePublic);
|
||||
}
|
||||
|
||||
$bookmark = isset($bookmarks[$bookmarkID]) ? $bookmarks[$bookmarkID] : null;
|
||||
|
||||
return $bookmark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL for a bookmark
|
||||
*
|
||||
* @param string $bookmarkID
|
||||
* @param User|null $user
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function getBookmarkUrl($bookmarkID, $user = null) {
|
||||
if(strpos($bookmarkID, $this->typePrefix(self::typeOwned)) === 0) {
|
||||
if($user) $bookmarkID = $user->id . $bookmarkID;
|
||||
} else {
|
||||
$bookmarkID = $this->intID($bookmarkID);
|
||||
}
|
||||
return $this->page->url . "bm$bookmarkID";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL for a bookmark
|
||||
*
|
||||
* @param string $bookmarkID
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function getBookmarkEditUrl($bookmarkID) {
|
||||
return $this->page->url . "edit-bookmark/?bookmark=$bookmarkID";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the title for the given bookmark ID or bookmark array
|
||||
*
|
||||
* @param int|array $bookmarkID
|
||||
* @return mixed|string
|
||||
* @throws WireException
|
||||
*
|
||||
*/
|
||||
public function getBookmarkTitle($bookmarkID) {
|
||||
if(is_array($bookmarkID)) {
|
||||
$bookmark = $bookmarkID;
|
||||
} else {
|
||||
$bookmark = $this->getBookmark($bookmarkID);
|
||||
if(empty($bookmark)) return '';
|
||||
}
|
||||
$languages = $this->wire('languages');
|
||||
$title = $bookmark['title'];
|
||||
if($languages) {
|
||||
$user = $this->wire('user');
|
||||
if(!$user->language->isDefault() && !empty($bookmark["title$user->language"])) {
|
||||
$title = $bookmark["title$user->language"];
|
||||
}
|
||||
}
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bookmark by ID
|
||||
*
|
||||
* @param int $bookmarkID
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function deleteBookmarkByID($bookmarkID) {
|
||||
|
||||
$bookmark = $this->getBookmark($bookmarkID);
|
||||
|
||||
if(!$bookmark) return false;
|
||||
if(!$this->isBookmarkDeletable($bookmark)) return false;
|
||||
|
||||
if($bookmark['type'] == self::typeOwned) {
|
||||
$bookmarks = $this->getOwnedBookmarks();
|
||||
unset($bookmarks[$bookmarkID]);
|
||||
$this->saveOwnedBookmarks($bookmarks);
|
||||
} else {
|
||||
$bookmarks = $this->getPublicBookmarks();
|
||||
unset($bookmarks[$bookmarkID]);
|
||||
$this->savePublicBookmarks($bookmarks);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter bookmarks, removing those that are not of the requested type
|
||||
*
|
||||
* @param array $allBookmarks
|
||||
* @param int $type
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
public function filterBookmarksByType(array $allBookmarks, $type) {
|
||||
$filteredBookmarks = array();
|
||||
foreach($allBookmarks as $key => $bookmark) {
|
||||
if(!isset($bookmark['type'])) $bookmark['type'] = self::typePublic;
|
||||
if($bookmark['type'] != $type) continue;
|
||||
$filteredBookmarks[$key] = $bookmark;
|
||||
}
|
||||
return $filteredBookmarks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter bookmarks, removing those user does not have access to
|
||||
*
|
||||
* @param array $bookmarks
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
public function filterBookmarksByAccess(array $bookmarks) {
|
||||
foreach($bookmarks as $key => $bookmark) {
|
||||
if(!$this->isBookmarkViewable($bookmark)) unset($bookmarks[$key]);
|
||||
}
|
||||
return $bookmarks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the given bookmark editable?
|
||||
*
|
||||
* @param array $bookmark
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function isBookmarkEditable(array $bookmark) {
|
||||
if($this->user->isSuperuser()) return true;
|
||||
if($bookmark['type'] == self::typePublic) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the given bookmark viewable?
|
||||
*
|
||||
* @param array $bookmark
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function isBookmarkViewable(array $bookmark) {
|
||||
|
||||
if(empty($bookmark['roles'])) return true;
|
||||
if($this->user->isSuperuser()) return true;
|
||||
|
||||
$userRoles = $this->user->roles;
|
||||
$viewable = false;
|
||||
|
||||
foreach($bookmark['roles'] as $roleID) {
|
||||
foreach($userRoles as $userRole) {
|
||||
if($userRole->id == $roleID) {
|
||||
$viewable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $viewable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the given bookmark deletable?
|
||||
*
|
||||
* @param array $bookmark
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function isBookmarkDeletable(array $bookmark) {
|
||||
return $this->isBookmarkEditable($bookmark);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a template array for a bookmark
|
||||
*
|
||||
* @param array $bookmark
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
public function _bookmark(array $bookmark = array()) {
|
||||
$template = array(
|
||||
'id' => '',
|
||||
'title' => '',
|
||||
'desc' => '',
|
||||
'selector' => '',
|
||||
'columns' => array(),
|
||||
'sort' => '',
|
||||
'type' => self::typePublic,
|
||||
'roles' => array(),
|
||||
'share' => false,
|
||||
);
|
||||
|
||||
return empty($bookmark) ? $template : array_merge($template, $bookmark);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a bookmark ID
|
||||
*
|
||||
* @param string|array $bookmarkID
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function _bookmarkID($bookmarkID) {
|
||||
if(is_array($bookmarkID)) {
|
||||
$bookmark = $bookmarkID;
|
||||
$type = $bookmark['type'];
|
||||
$bookmarkID = $bookmark['id'];
|
||||
} else {
|
||||
$type = self::typePublic;
|
||||
$ownedPrefix = $this->typePrefix(self::typeOwned);
|
||||
if(strpos($bookmarkID, $ownedPrefix) !== false) {
|
||||
list($userID, $bookmarkID) = explode($ownedPrefix, $bookmarkID);
|
||||
$userID = empty($userID) ? '' : (int) $userID;
|
||||
$bookmarkID = $userID . $ownedPrefix . ((int) $bookmarkID);
|
||||
return $bookmarkID;
|
||||
} else {
|
||||
$bookmarkID = ltrim($bookmarkID, $this->typePrefix(self::typePublic));
|
||||
}
|
||||
}
|
||||
if(!ctype_digit("$bookmarkID")) return '';
|
||||
return $this->typePrefix($type) . ((int) $bookmarkID);
|
||||
}
|
||||
|
||||
protected function getModuleConfig() {
|
||||
if($this->moduleConfig === null) {
|
||||
$this->moduleConfig = $this->wire('modules')->getConfig('ProcessPageLister');
|
||||
}
|
||||
if(!isset($this->moduleConfig['bookmarks'])) $this->moduleConfig['bookmarks'] = array();
|
||||
return $this->moduleConfig;
|
||||
}
|
||||
|
||||
protected function setModuleConfig(array $moduleConfig) {
|
||||
$this->moduleConfig = $moduleConfig;
|
||||
}
|
||||
|
||||
protected function saveModuleConfig(array $moduleConfig) {
|
||||
if($moduleConfig === $this->moduleConfig) return false;
|
||||
$this->wire('modules')->saveConfig('ProcessPageLister', $moduleConfig);
|
||||
$this->moduleConfig = $moduleConfig;
|
||||
$this->message('Updated module config (bookmarks)', Notice::debug);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function wakeupBookmark(array $bookmark, $bookmarkID, $type = null) {
|
||||
|
||||
if(empty($bookmarkID) || empty($bookmark['title'])) return false;
|
||||
|
||||
if($type === null) $type = $this->idType($bookmarkID);
|
||||
$bookmarkID = $this->bookmarkStrID($bookmarkID, $type);
|
||||
|
||||
$bookmark = $this->_bookmark($bookmark);
|
||||
$bookmark['type'] = $type;
|
||||
$bookmark['id'] = $bookmarkID;
|
||||
$bookmark['url'] = $this->getBookmarkUrl($bookmarkID);
|
||||
$bookmark['editUrl'] = $this->getBookmarkEditUrl($bookmarkID);
|
||||
$bookmark['share'] = empty($bookmark['share']) ? false : true;
|
||||
//$bookmark['shareUrl'] = $bookmark['url'];
|
||||
|
||||
return $bookmark;
|
||||
}
|
||||
|
||||
protected function sleepBookmark(array $bookmark) {
|
||||
unset($bookmark['id'], $bookmark['url'], $bookmark['editUrl']);
|
||||
if($bookmark['type'] === self::typeOwned) unset($bookmark['roles']);
|
||||
if(empty($bookmark['share'])) unset($bookmark['share']);
|
||||
return $bookmark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an id or string key, return an int ID
|
||||
*
|
||||
* @param string|int $val
|
||||
* @return int
|
||||
*
|
||||
*/
|
||||
public function intID($val) {
|
||||
return (int) ltrim($val, '_O');
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an id or string key, return an string ID (with leading underscore)
|
||||
*
|
||||
* @param string|int $val
|
||||
* @return int
|
||||
*
|
||||
*/
|
||||
public function strID($val) {
|
||||
return '_' . ltrim($val, '_O');
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an id or string key, return an bookmark string ID
|
||||
*
|
||||
* @param string|int $val
|
||||
* @param int $type
|
||||
* @return int
|
||||
*
|
||||
*/
|
||||
public function bookmarkStrID($val, $type) {
|
||||
return ($type === self::typeOwned ? 'O' : '_') . ltrim($val, '_O');
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the given string value represent an ID? If yes, return ID, otherwise return false.
|
||||
*
|
||||
* @param string $val
|
||||
* @return bool|int
|
||||
*
|
||||
*/
|
||||
public function isID($val) {
|
||||
$val = trim($val, '_O');
|
||||
return ctype_digit($val) ? (int) $val : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type from the given id string
|
||||
*
|
||||
* @param string $val
|
||||
* @return int
|
||||
*
|
||||
*/
|
||||
public function idType($val) {
|
||||
if(strpos($val, 'O') === 0) return self::typeOwned;
|
||||
return self::typePublic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the prefix for the given bookmark type
|
||||
*
|
||||
* @param int $type
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function typePrefix($type) {
|
||||
if($type == self::typePublic) return '_';
|
||||
if($type == self::typeOwned) return 'O';
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the given page ID or key valid and existing?
|
||||
*
|
||||
* @param int|string $val
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function isValidPageKey($val) {
|
||||
$id = $this->intID($val);
|
||||
return $id === $this->page->id || $this->wire('pages')->get($id)->id > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a readable selector from bookmark for output purposes
|
||||
*
|
||||
* @param array $bookmark
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function readableBookmarkSelector(array $bookmark) {
|
||||
|
||||
$selector = $bookmark['selector'];
|
||||
if(strpos($selector, 'template=') !== false && preg_match('/template=([\d\|]+)/', $selector, $matches)) {
|
||||
// make templates readable, for output purposes
|
||||
$t = '';
|
||||
foreach(explode('|', $matches[1]) as $templateID) {
|
||||
$template = $this->wire('templates')->get((int) $templateID);
|
||||
$t .= ($t ? '|' : '') . ($template ? $template->name : $templateID);
|
||||
}
|
||||
$selector = str_replace($matches[0], "template=$t", $selector);
|
||||
}
|
||||
|
||||
if(!empty($bookmark['sort'])) $selector .= ($selector ? ", " : "") . "sort=$bookmark[sort]";
|
||||
|
||||
return $selector;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -1 +1 @@
|
||||
#ProcessLister{margin-top:-2px}#ProcessListerResultsTab{padding-top:.5em}#ProcessListerResults>form.InputfieldForm{margin-bottom:0}#ProcessListerResults #ProcessListerTable{clear:both;overflow-x:auto}#ProcessListerResults #ProcessListerTable>div{margin-top:0}#ProcessListerResults #ProcessListerTable table.ProcessListerTable{clear:both;margin-top:0}#ProcessListerResults #ProcessListerTable table.ProcessListerTable td table{width:100%}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>thead th{font-size:.8571428571em}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>thead th i{font-size:14px}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>thead th strong{white-space:nowrap}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>thead th b,#ProcessListerResults #ProcessListerTable table.ProcessListerTable>thead .th b{display:none}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>thead th:first-child{padding-left:0}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td{font-size:.9285714286em}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td:first-child,#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td:first-child>a{padding-left:0}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td ul.MarkupFieldtype{margin:0;padding-left:0}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td ul.MarkupFieldtype>li{list-style:none;margin:0;padding-left:0}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td ul.MarkupFieldtype>li+li{border-top:1px solid #eee}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td>*:first-child,#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td .col_preview>*:first-child{margin-top:0}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td>*:last-child,#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td .col_preview>*:last-child{margin-bottom:0}#ProcessListerResults .PageListerActions{display:none;line-height:1.3em;text-transform:lowercase}#ProcessListerResults .PageListerActions a.PageExtra{margin-bottom:3px}#ProcessListerResults .PageListerActions a.PageExtras i{margin-left:3px;margin-right:2px}#ProcessListerResults .PageListerActions a.PageExtras.open i{margin-left:2px;margin-right:3px}#ProcessListerResults .row_message{display:inline}#ProcessListerResults .PageListStatusUnpublished{text-decoration:line-through;opacity:.5}#ProcessListerResults .PageListStatusHidden{opacity:.5}#ProcessListerResults .MarkupPagerNav{float:right}#ProcessListerResults .nobr{white-space:nowrap}#ProcessListerResults table+.MarkupPagerNav{margin:0}#ProcessListerResults .datetime{white-space:nowrap}#ProcessListerResults td:not(.col_editing) .InputfieldHasFileList .InputfieldHeader{display:none}#ProcessListerResults td:not(.col_editing) .InputfieldHasFileList .InputfieldContent{padding:5px;border:none;margin-top:5px;margin-bottom:5px}@media only screen and (max-width: 767px){#ProcessListerResults table.ProcessListerTable+.MarkupPagerNav{margin-bottom:1em}#ProcessListerResults .MarkupPagerNav{float:none}}.AdminDataTable p{margin:1em 0}#ProcessListerResults+a button{float:left;margin-right:0;margin-top:0}#ProcessListerSpinner{margin-left:.5em;font-size:20px;position:relative}#ProcessListerSpinner i{position:absolute;top:-15px;left:0}.pw-content .lister_headline,#content .lister_headline{float:left;margin-top:1em}@media only screen and (max-width: 767px){.pw-content .lister_headline,#content .lister_headline{float:none;clear:both}}#lister_open_cnt{display:none}#filters_spinner{float:right;margin-top:4px}#ProcessListerRefreshTab{float:right}#ProcessListerSelector{display:inline-block}p.version{clear:both;padding-top:1em}#ProcessListerScript{display:none}#table_bookmarks{margin-top:.5em}.AdminThemeReno a.lister-lightbox{padding:0 !important}.AdminThemeReno a.lister-lightbox img{margin:0 !important}.AdminThemeReno #content .lister_headline{margin-top:.5em}#ProcessListerTable .InputfieldFile .InputfieldContent,#ProcessListerTable .InputfieldFile .InputfieldHeader,#ProcessListerTable .InputfieldImage .InputfieldContent,#ProcessListerTable .InputfieldImage .InputfieldHeader{background:inherit}#ProcessListerTable .InputfieldFile .InputfieldHeader,#ProcessListerTable .InputfieldImage .InputfieldHeader{padding-left:0;padding-right:0;padding-top:0}#ProcessListerTable .InputfieldFile .gridImage__tooltip table th,#ProcessListerTable .InputfieldFile .gridImage__tooltip table td,#ProcessListerTable .InputfieldImage .gridImage__tooltip table th,#ProcessListerTable .InputfieldImage .gridImage__tooltip table td{padding:0}
|
||||
#ProcessLister{margin-top:-2px}#ProcessListerResultsTab{padding-top:.5em}#ProcessListerResults>form.InputfieldForm{margin-bottom:0}#ProcessListerResults #ProcessListerTable{clear:both;overflow-x:auto}#ProcessListerResults #ProcessListerTable>div{margin-top:0}#ProcessListerResults #ProcessListerTable table.ProcessListerTable{clear:both;margin-top:0}#ProcessListerResults #ProcessListerTable table.ProcessListerTable td table{width:100%}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>thead th{font-size:.8571428571em}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>thead th i{font-size:14px}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>thead th strong{white-space:nowrap}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>thead th b,#ProcessListerResults #ProcessListerTable table.ProcessListerTable>thead .th b{display:none}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>thead th:first-child{padding-left:0}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td{font-size:.9285714286em}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td:first-child,#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td:first-child>a{padding-left:0}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td ul.MarkupFieldtype{margin:0;padding-left:0}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td ul.MarkupFieldtype>li{list-style:none;margin:0;padding-left:0}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td ul.MarkupFieldtype>li+li{border-top:1px solid #eee}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td>*:first-child,#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td .col_preview>*:first-child{margin-top:0}#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td>*:last-child,#ProcessListerResults #ProcessListerTable table.ProcessListerTable>tbody>tr>td .col_preview>*:last-child{margin-bottom:0}#ProcessListerResults .PageListerActions{display:none;line-height:1.3em;text-transform:lowercase}#ProcessListerResults .PageListerActions a.PageExtra{margin-bottom:3px}#ProcessListerResults .PageListerActions a.PageExtras i{margin-left:3px;margin-right:2px}#ProcessListerResults .PageListerActions a.PageExtras.open i{margin-left:2px;margin-right:3px}#ProcessListerResults .row_message{display:inline}#ProcessListerResults .PageListStatusUnpublished{text-decoration:line-through;opacity:.5}#ProcessListerResults .PageListStatusHidden{opacity:.5}#ProcessListerResults .MarkupPagerNav{float:right}#ProcessListerResults .nobr{white-space:nowrap}#ProcessListerResults table+.MarkupPagerNav{margin:0}#ProcessListerResults .datetime{white-space:nowrap}#ProcessListerResults td:not(.col_editing) .InputfieldHasFileList .InputfieldHeader{display:none}#ProcessListerResults td:not(.col_editing) .InputfieldHasFileList .InputfieldContent{padding:5px;border:none;margin-top:5px;margin-bottom:5px}@media only screen and (max-width: 767px){#ProcessListerResults table.ProcessListerTable+.MarkupPagerNav{margin-bottom:1em}#ProcessListerResults .MarkupPagerNav{float:none}}.AdminDataTable p{margin:1em 0}#ProcessListerResults+a button{float:left;margin-right:0;margin-top:0}#ProcessListerSpinner{margin-left:.5em;font-size:20px;position:relative}#ProcessListerSpinner i{position:absolute;top:-15px;left:0}.pw-content .lister_headline,#content .lister_headline{float:left;margin-top:1em}@media only screen and (max-width: 767px){.pw-content .lister_headline,#content .lister_headline{float:none;clear:both}}#lister_open_cnt{display:none}#filters_spinner{float:right;margin-top:4px}#ProcessListerRefreshTab{float:right}#ProcessListerSelector{display:inline-block}#ProcessListerResultNotes+#ProcessListerSelector{margin-top:0}p.version{clear:both;padding-top:1em}#ProcessListerScript{display:none}#tab_bookmarks table tr>td:first-child{width:30%}#tab_bookmarks table tr>td:nth-child(2){width:40%}.AdminThemeReno a.lister-lightbox{padding:0 !important}.AdminThemeReno a.lister-lightbox img{margin:0 !important}.AdminThemeReno #content .lister_headline{margin-top:.5em}#ProcessListerTable .InputfieldFile .InputfieldContent,#ProcessListerTable .InputfieldFile .InputfieldHeader,#ProcessListerTable .InputfieldImage .InputfieldContent,#ProcessListerTable .InputfieldImage .InputfieldHeader{background:inherit}#ProcessListerTable .InputfieldFile .InputfieldHeader,#ProcessListerTable .InputfieldImage .InputfieldHeader{padding-left:0;padding-right:0;padding-top:0}#ProcessListerTable .InputfieldFile .gridImage__tooltip table th,#ProcessListerTable .InputfieldFile .gridImage__tooltip table td,#ProcessListerTable .InputfieldImage .gridImage__tooltip table th,#ProcessListerTable .InputfieldImage .gridImage__tooltip table td{padding:0}
|
||||
|
@@ -146,6 +146,14 @@ class ProcessPageLister extends Process implements ConfigurableModule {
|
||||
*/
|
||||
protected $openPageIDs = array();
|
||||
|
||||
/**
|
||||
* Additional notes about the results to display underneath them
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
*/
|
||||
protected $resultNotes = array();
|
||||
|
||||
/**
|
||||
* Initalize module config variables
|
||||
*
|
||||
@@ -348,35 +356,25 @@ class ProcessPageLister extends Process implements ConfigurableModule {
|
||||
/**
|
||||
* Check for a bookmark specified in GET variable $n
|
||||
*
|
||||
* return null|int|bool Returns NULL if not applicable, boolean false if bookmark not found, or integer of bookmark ID if applied
|
||||
* @param string $bookmarkID
|
||||
* @return null|int|bool Returns NULL if not applicable, boolean false if bookmark not found, or integer of bookmark ID if applied
|
||||
*
|
||||
*/
|
||||
public function checkBookmark() {
|
||||
$n = (int) $this->wire('input')->get('bookmark');
|
||||
if(!$n) return null;
|
||||
$bookmarks = $this->getBookmarksInstance()->getBookmarks();
|
||||
if(!isset($bookmarks[$n])) return false;
|
||||
$bookmark = $bookmarks[$n];
|
||||
$user = $this->wire('user');
|
||||
if(!$user->isSuperuser() && count($bookmark['roles'])) {
|
||||
$allow = false;
|
||||
foreach($bookmark['roles'] as $roleID) {
|
||||
foreach($user->roles as $role) {
|
||||
if($role->id == $roleID) {
|
||||
$allow = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!$allow) return false;
|
||||
}
|
||||
public function checkBookmark($bookmarkID = '') {
|
||||
if(!$bookmarkID) $bookmarkID = $this->wire('input')->get('bookmark');
|
||||
if(!$bookmarkID) return null;
|
||||
$bookmarks = $this->getBookmarksInstance();
|
||||
$bookmarkID = $bookmarks->_bookmarkID($bookmarkID);
|
||||
if(!$bookmarkID) return false;
|
||||
$bookmark = $bookmarks->getBookmark($bookmarkID);
|
||||
if(!$bookmark || !$bookmarks->isBookmarkViewable($bookmark)) return false;
|
||||
$this->sessionClear();
|
||||
$this->set('defaultSelector', $bookmark['selector']);
|
||||
$this->set('defaultSort', $bookmark['sort']);
|
||||
$this->sessionSet('sort', $bookmark['sort']);
|
||||
$this->set('columns', $bookmark['columns']);
|
||||
|
||||
return $n;
|
||||
$this->headline($this->wire('page')->title . ' - ' . $bookmark['title']);
|
||||
return $bookmarkID;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1009,7 +1007,9 @@ class ProcessPageLister extends Process implements ConfigurableModule {
|
||||
// ok, override
|
||||
} else {
|
||||
$selectors->remove($s);
|
||||
if($value && $showIncludeWarnings) $this->error($this->_("Specified 'include=' mode is not allowed here."));
|
||||
if($value && $showIncludeWarnings) {
|
||||
$this->resultNotes[] = $this->_("Specified 'include=' mode is not allowed here.") . " (include=$value)";
|
||||
}
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
@@ -1039,7 +1039,9 @@ class ProcessPageLister extends Process implements ConfigurableModule {
|
||||
// include=unpublished is allowed
|
||||
} else if($includeMode == 'unpublished') {
|
||||
// include=unpublished is not allowed
|
||||
if($showIncludeWarnings) $this->error($this->_("Not all specified templates are editable. Only 'include=hidden' is allowed"));
|
||||
if($showIncludeWarnings) {
|
||||
$this->resultNotes[] = $this->_("Not all specified templates are editable. Only 'include=hidden' is allowed");
|
||||
}
|
||||
$includeSelector->value = 'hidden';
|
||||
$changed = true;
|
||||
}
|
||||
@@ -1049,7 +1051,9 @@ class ProcessPageLister extends Process implements ConfigurableModule {
|
||||
// only allow a max include mode of hidden
|
||||
// regardless of edit access
|
||||
if($includeMode != 'hidden') {
|
||||
if($showIncludeWarnings) $this->error($this->_("No templates specified so 'include=hidden' is max allowed include mode"));
|
||||
if($showIncludeWarnings) {
|
||||
$this->resultNotes[] = $this->_("No templates specified so 'include=hidden' is max allowed include mode");
|
||||
}
|
||||
$includeSelector->value = 'hidden';
|
||||
$changed = true;
|
||||
}
|
||||
@@ -1783,9 +1787,15 @@ class ProcessPageLister extends Process implements ConfigurableModule {
|
||||
"<div id='ProcessListerTable'>$tableOut</div>" .
|
||||
$pagerOut;
|
||||
|
||||
if(count($this->resultNotes)) {
|
||||
$notes = array();
|
||||
foreach($this->resultNotes as $note) {
|
||||
$notes[] = wireIconMarkup('warning') . ' ' . $this->wire('sanitizer')->entities1($note);
|
||||
}
|
||||
$out .= "<p id='ProcessListerResultNotes' class='detail'>" . implode('<br />', $notes) . "</p>";
|
||||
}
|
||||
if($this->wire('config')->debug) {
|
||||
$out .= "<p id='ProcessListerSelector' class='notes'>" . $this->wire('sanitizer')->entities($this->finalSelector) . "</p>";
|
||||
//$out .= "<p id='ProcessListerSelector' class='notes'>" . $this->wire('sanitizer')->entities($findSelector) . "</p>";
|
||||
}
|
||||
|
||||
if(!$this->editOption) {
|
||||
@@ -1889,9 +1899,7 @@ class ProcessPageLister extends Process implements ConfigurableModule {
|
||||
}
|
||||
if($this->allowBookmarks) {
|
||||
$bookmarks = $this->getBookmarksInstance();
|
||||
if($this->wire('user')->isSuperuser() || count($bookmarks->getBookmarks())) {
|
||||
$out .= $bookmarks->buildBookmarkListForm()->render();
|
||||
}
|
||||
$out .= $bookmarks->buildBookmarkListForm()->render();
|
||||
}
|
||||
$out .= $this->renderExtras();
|
||||
}
|
||||
@@ -2096,7 +2104,27 @@ class ProcessPageLister extends Process implements ConfigurableModule {
|
||||
*/
|
||||
public function ___executeEditBookmark() {
|
||||
if(!$this->allowBookmarks) throw new WireException("Bookmarks are disabled");
|
||||
return $this->getBookmarksInstance()->editBookmark();
|
||||
return $this->getBookmarksInstance()->executeEditBookmark();
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch-all for bookmarks
|
||||
*
|
||||
* @return string
|
||||
* @throws Wire404Exception
|
||||
* @throws WireException
|
||||
*
|
||||
*/
|
||||
public function ___executeUnknown() {
|
||||
$bookmarkID = $this->wire('input')->urlSegment1;
|
||||
if(strpos($bookmarkID, 'bm') === 0) {
|
||||
$bookmarks = $this->getBookmarksInstance();
|
||||
$bookmarkID = $bookmarks->_bookmarkID(ltrim($bookmarkID, 'bm'));
|
||||
} else {
|
||||
$bookmarkID = '';
|
||||
}
|
||||
if(!$bookmarkID || !$this->checkBookmark($bookmarkID)) throw new Wire404Exception();
|
||||
return $this->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2123,13 +2151,14 @@ class ProcessPageLister extends Process implements ConfigurableModule {
|
||||
$user = $this->wire('user');
|
||||
$languageID = $languages && !$user->language->isDefault() ? $user->language->id : '';
|
||||
|
||||
foreach($bookmarks as $n => $bookmark) {
|
||||
foreach($bookmarks as $bookmarkID => $bookmark) {
|
||||
$name = $bookmark['title'];
|
||||
$icon = $bookmark['type'] ? 'user-circle-o' : 'search';
|
||||
if($languageID && !empty($bookmark["title$languageID"])) $name = $bookmark["title$languageID"];
|
||||
$item = array(
|
||||
'id' => $n,
|
||||
'id' => $bookmarkID,
|
||||
'name' => $name,
|
||||
'icon' => 'search',
|
||||
'icon' => $icon,
|
||||
);
|
||||
$items[] = $item;
|
||||
}
|
||||
|
@@ -201,6 +201,9 @@
|
||||
#ProcessListerSelector {
|
||||
display: inline-block;
|
||||
}
|
||||
#ProcessListerResultNotes + #ProcessListerSelector {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
p.version {
|
||||
clear: both;
|
||||
@@ -211,10 +214,18 @@ p.version {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#table_bookmarks {
|
||||
margin-top: 0.5em;
|
||||
#tab_bookmarks {
|
||||
table tr {
|
||||
> td:first-child {
|
||||
width: 30%;
|
||||
}
|
||||
> td:nth-child(2) {
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.AdminThemeReno {
|
||||
a.lister-lightbox {
|
||||
padding: 0 !important;
|
||||
|
@@ -8,51 +8,73 @@
|
||||
*/
|
||||
class ProcessPageListerBookmarks extends Wire {
|
||||
|
||||
/**
|
||||
* @var ProcessPageLister
|
||||
*
|
||||
*/
|
||||
protected $lister;
|
||||
|
||||
/**
|
||||
* @var ListerBookmarks
|
||||
*
|
||||
*/
|
||||
protected $bookmarks;
|
||||
|
||||
/**
|
||||
* @var Page
|
||||
*
|
||||
*/
|
||||
protected $page;
|
||||
|
||||
/**
|
||||
* @var User
|
||||
*
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param ProcessPageLister $lister
|
||||
*
|
||||
*/
|
||||
public function __construct(ProcessPageLister $lister) {
|
||||
require_once(__DIR__ . '/ListerBookmarks.php');
|
||||
$this->lister = $lister;
|
||||
$this->page = $lister->wire('page');
|
||||
$this->user = $lister->wire('user');
|
||||
$this->bookmarks = new ListerBookmarks($this->page, $this->user);
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get configured bookmarks allowed for current user
|
||||
*
|
||||
* @return array
|
||||
* @return ListerBookmarks
|
||||
*
|
||||
*/
|
||||
public function getBookmarks() {
|
||||
public function bookmarks() {
|
||||
return $this->bookmarks;
|
||||
}
|
||||
|
||||
$page = $this->wire('page');
|
||||
$key = "_$page->id";
|
||||
$data = $this->wire('modules')->getModuleConfigData('ProcessPageLister');
|
||||
$_bookmarks = isset($data['bookmarks'][$key]) ? $data['bookmarks'][$key] : array();
|
||||
$bookmarks = array();
|
||||
/**
|
||||
* Set the Lister page that bookmarks will be for
|
||||
*
|
||||
* @param Page $page
|
||||
*
|
||||
*/
|
||||
public function setPage(Page $page) {
|
||||
$this->page = $page;
|
||||
$this->bookmarks->setPage($page);
|
||||
}
|
||||
|
||||
foreach($_bookmarks as $n => $bookmark) {
|
||||
$n = (int) ltrim($n, '_');
|
||||
$bookmark['url'] = $this->wire('page')->url . "?bookmark=$n";
|
||||
$bookmarks[$n] = $bookmark;
|
||||
}
|
||||
|
||||
if(!$this->wire('user')->isSuperuser()) {
|
||||
$userRoles = $this->wire('user')->roles;
|
||||
foreach($bookmarks as $n => $bookmark) {
|
||||
$allowBookmark = false;
|
||||
if(empty($bookmark['roles'])) {
|
||||
$allowBookmark = true;
|
||||
} else foreach($bookmark['roles'] as $roleID) {
|
||||
foreach($userRoles as $userRole) {
|
||||
if($userRole->id == $roleID) {
|
||||
$allowBookmark = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!$allowBookmark) unset($bookmarks[$n]);
|
||||
}
|
||||
}
|
||||
|
||||
return $bookmarks;
|
||||
/**
|
||||
* Set user that bookmarks will be for
|
||||
*
|
||||
* @param User $user
|
||||
*
|
||||
*/
|
||||
public function setUser(User $user) {
|
||||
$this->user = $user;
|
||||
$this->bookmarks->setUser($user);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,6 +85,9 @@ class ProcessPageListerBookmarks extends Wire {
|
||||
*/
|
||||
public function buildBookmarkListForm() {
|
||||
|
||||
/** @var Sanitizer $sanitizer */
|
||||
$sanitizer = $this->wire('sanitizer');
|
||||
|
||||
/** @var InputfieldForm $form */
|
||||
$form = $this->modules->get('InputfieldForm');
|
||||
$form->attr('id', 'tab_bookmarks');
|
||||
@@ -71,180 +96,318 @@ class ProcessPageListerBookmarks extends Wire {
|
||||
$form->class .= ' WireTab';
|
||||
$form->attr('title', $this->_x('Bookmarks', 'tab'));
|
||||
|
||||
$user = $this->wire('user');
|
||||
$bookmarks = $this->getBookmarks();
|
||||
$superuser = $user->isSuperuser();
|
||||
$publicBookmarks = $this->bookmarks->getPublicBookmarks();
|
||||
$ownedBookmarks = $this->bookmarks->getOwnedBookmarks();
|
||||
|
||||
/** @var Languages $languages */
|
||||
$languages = $this->wire('languages');
|
||||
$languageID = $languages && !$user->language->isDefault() ? $user->language->id : '';
|
||||
$languageID = $languages && !$this->user->language->isDefault() ? $this->user->language->id : '';
|
||||
|
||||
if($superuser) {
|
||||
$fieldset = $this->buildBookmarkEditForm(0, $bookmarks);
|
||||
if(count($bookmarks)) $fieldset->collapsed = Inputfield::collapsedYes;
|
||||
$form->add($fieldset);
|
||||
}
|
||||
$addBookmarkFieldset = $this->buildBookmarkEditForm(0);
|
||||
$addBookmarkFieldset->collapsed = Inputfield::collapsedYes;
|
||||
$form->add($addBookmarkFieldset);
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldMarkup');
|
||||
$f->label = $form->attr('title');
|
||||
$f->icon = 'bookmark-o';
|
||||
$form->add($f);
|
||||
$bookmarksByType = array(
|
||||
ListerBookmarks::typeOwned => $ownedBookmarks,
|
||||
ListerBookmarks::typePublic => $publicBookmarks,
|
||||
);
|
||||
|
||||
if(!count($bookmarks)) return $form;
|
||||
$iconsByType = array(
|
||||
ListerBookmarks::typeOwned => 'user-circle-o',
|
||||
ListerBookmarks::typePublic => 'bookmark-o',
|
||||
);
|
||||
|
||||
// render table of current bookmarks
|
||||
$table = $this->wire('modules')->get('MarkupAdminDataTable');
|
||||
$table->setID('table_bookmarks');
|
||||
$table->setSortable(false);
|
||||
$headerRow = array($this->_x('Bookmark', 'bookmark-th'));
|
||||
if($superuser) {
|
||||
$headerRow[] = $this->_x('Selector', 'bookmark-th');
|
||||
$headerRow[] = $this->_x('Columns', 'bookmark-th');
|
||||
$headerRow[] = $this->_x('Access', 'bookmark-th');
|
||||
$headerRow[] = $this->_x('Action', 'bookmark-th');
|
||||
}
|
||||
$table->headerRow($headerRow);
|
||||
foreach($bookmarks as $n => $bookmark) {
|
||||
$row = array();
|
||||
$title = $bookmark['title'];
|
||||
if($languageID && !empty($bookmark["title$languageID"])) $title = $bookmark["title$languageID"];
|
||||
$row["$title\0"] = $bookmark['url'];
|
||||
if($superuser) {
|
||||
$selector = $bookmark['selector'];
|
||||
if(strpos($selector, 'template=') !== false && preg_match('/template=([\d\|]+)/', $selector, $matches)) {
|
||||
// make templates readable, for output purposes
|
||||
$t = '';
|
||||
foreach(explode('|', $matches[1]) as $templateID) {
|
||||
$template = $this->wire('templates')->get((int) $templateID);
|
||||
$t .= ($t ? '|' : '') . ($template ? $template->name : $templateID);
|
||||
$typeLabels = array(
|
||||
ListerBookmarks::typeOwned => $this->_('My bookmarks'),
|
||||
ListerBookmarks::typePublic => $this->_('Public bookmarks')
|
||||
);
|
||||
|
||||
foreach($bookmarksByType as $bookmarkType => $bookmarks) {
|
||||
|
||||
if(empty($bookmarks)) continue;
|
||||
|
||||
/** @var InputfieldMarkup $f */
|
||||
$f = $this->wire('modules')->get('InputfieldMarkup');
|
||||
$f->label = $typeLabels[$bookmarkType];
|
||||
$f->icon = $iconsByType[$bookmarkType];
|
||||
|
||||
$headerRow = array(
|
||||
0 => $this->_x('Bookmark', 'bookmark-th'),
|
||||
1 => $this->_x('Description', 'bookmark-th'),
|
||||
2 => $this->_x('Access', 'bookmark-th'),
|
||||
3 => $this->_x('Actions', 'bookmark-th'),
|
||||
);
|
||||
|
||||
/** @var MarkupAdminDataTable $table */
|
||||
$table = $this->wire('modules')->get('MarkupAdminDataTable');
|
||||
$table->setID('table_bookmarks_' . $bookmarkType);
|
||||
$table->setSortable(false);
|
||||
$table->setEncodeEntities(false);
|
||||
$table->headerRow($headerRow);
|
||||
|
||||
foreach($bookmarks as $bookmarkID => $bookmark) {
|
||||
|
||||
$row = array();
|
||||
if(!$this->bookmarks->isBookmarkViewable($bookmark)) continue;
|
||||
|
||||
// title column
|
||||
$title = $bookmark['title'];
|
||||
if($languageID && !empty($bookmark["title$languageID"])) $title = $bookmark["title$languageID"];
|
||||
$title = $sanitizer->entities($title);
|
||||
$viewUrl = $this->bookmarks->getBookmarkUrl($bookmarkID, $this->user);
|
||||
$row["$title\0"] = $viewUrl;
|
||||
|
||||
// description column
|
||||
$desc = $bookmark['desc'];
|
||||
if($languageID && !empty($bookmark["desc$languageID"])) $desc = $bookmark["desc$languageID"];
|
||||
if(empty($desc)) {
|
||||
$selector = $this->bookmarks->readableBookmarkSelector($bookmark);
|
||||
$columns = implode(', ', $bookmark['columns']);
|
||||
$desc = "$selector ($columns)";
|
||||
}
|
||||
$row[] = $sanitizer->entities($desc);
|
||||
|
||||
// access column (public bookmarks only)
|
||||
if($bookmark['type'] == ListerBookmarks::typePublic) {
|
||||
if(count($bookmark['roles']) < 2 && ((int) reset($bookmark['roles'])) === 0) {
|
||||
$row[] = $this->_x('all', 'bookmark-roles');
|
||||
} else if(count($bookmark['roles'])) {
|
||||
$row[] = $this->wire('pages')->getById($bookmark['roles'])->implode(', ', 'name');
|
||||
}
|
||||
$selector = str_replace($matches[0], "template=$t", $selector);
|
||||
} else {
|
||||
$row[] = $this->_('you');
|
||||
}
|
||||
if($bookmark['sort']) $selector .= ($selector ? ", " : "") . "sort=$bookmark[sort]";
|
||||
$row[] = $selector;
|
||||
$row[] = implode(', ', $bookmark['columns']);
|
||||
if(count($bookmark['roles']) < 2 && ((int) reset($bookmark['roles'])) === 0) {
|
||||
$row[] = $this->_x('all', 'bookmark-roles');
|
||||
} else if(count($bookmark['roles'])) {
|
||||
$row[] = $this->wire('pages')->getById($bookmark['roles'])->implode(', ', 'name');
|
||||
|
||||
// actions column
|
||||
$actions = array();
|
||||
$actions[] = "<a href='$viewUrl'>" . $this->_x('View', 'bookmark-action') . "</a>";
|
||||
if($this->bookmarks->isBookmarkEditable($bookmark)) {
|
||||
$editUrl = $this->bookmarks->getBookmarkEditUrl($bookmarkID);
|
||||
$actions[] = "<a href='$editUrl'>" . $this->_x('Modify', 'bookmark-action') . "</a>";
|
||||
if($this->bookmarks->isBookmarkDeletable($bookmark)) {
|
||||
$actions[] = "<a href='$editUrl&delete=1'>" . $this->_x('Delete', 'bookmark-action') . "</a>";
|
||||
}
|
||||
}
|
||||
$row[$this->_x('Edit', 'bookmark-action')] = "./edit-bookmark/?n=$n";
|
||||
|
||||
$actions = implode(' / ', $actions);
|
||||
$row[] = $actions;
|
||||
|
||||
$table->row($row);
|
||||
}
|
||||
$table->row($row);
|
||||
|
||||
$f->value = $table->render();
|
||||
|
||||
$form->add($f);
|
||||
}
|
||||
if($superuser) $f->appendMarkup = "<p class='detail'>" . $this->_('Superuser note: other users can see and click bookmarks, but may not add or edit them.') . "</p>";
|
||||
$f->value = $table->render();
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build form for deleting a bookmark
|
||||
*
|
||||
* @param int $bookmarkID Bookmark ID
|
||||
*
|
||||
* @return InputfieldFieldset
|
||||
* @throws WireException
|
||||
* @throws WirePermissionException
|
||||
*
|
||||
*/
|
||||
protected function buildBookmarkDeleteForm($bookmarkID) {
|
||||
|
||||
$bookmark = $this->bookmarks->getBookmark($bookmarkID);
|
||||
if(!$bookmark) throw new WireException('Unknown bookmark');
|
||||
|
||||
/** @var InputfieldFieldset $fieldset */
|
||||
$fieldset = $this->wire('modules')->get('InputfieldFieldset');
|
||||
$fieldset->icon = 'trash-o';
|
||||
$fieldset->label = $this->_('Please check the box to confirm you want to delete this bookmark');
|
||||
|
||||
/** @var InputfieldCheckbox $f */
|
||||
$f = $this->wire('modules')->get('InputfieldCheckbox');
|
||||
$f->attr('name', 'delete_bookmark');
|
||||
$f->label = $this->_('Delete this bookmark?');
|
||||
$f->icon = 'trash-o';
|
||||
$f->attr('value', $bookmarkID);
|
||||
$fieldset->add($f);
|
||||
|
||||
/** @var InputfieldSubmit $submit */
|
||||
$submit = $this->wire('modules')->get('InputfieldSubmit');
|
||||
$submit->attr('name', 'submit_delete_bookmark');
|
||||
$submit->icon = 'trash-o';
|
||||
$fieldset->add($submit);
|
||||
|
||||
/** @var InputfieldButton $cancel */
|
||||
$cancel = $this->wire('modules')->get('InputfieldButton');
|
||||
$cancel->href = '../#tab_bookmarks';
|
||||
$cancel->setSecondary(true);
|
||||
$cancel->attr('value', $this->_('Cancel'));
|
||||
$fieldset->add($cancel);
|
||||
|
||||
return $fieldset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the form needed to edit/add bookmarks
|
||||
*
|
||||
* @param int $bookmarkID Specify bookmark ID if editing existing bookmark
|
||||
* @param array $bookmarks Optionally include list of all bookmarks to prevent this method from having to re-load them
|
||||
*
|
||||
* @return InputfieldWrapper
|
||||
*
|
||||
*/
|
||||
protected function buildBookmarkEditForm($bookmarkID = 0, $bookmarks = array()) {
|
||||
protected function buildBookmarkEditForm($bookmarkID = 0) {
|
||||
|
||||
/** @var Languages $languages */
|
||||
$languages = $this->wire('languages');
|
||||
|
||||
/** @var InputfieldFieldset $fieldset */
|
||||
$fieldset = $this->wire('modules')->get('InputfieldFieldset');
|
||||
|
||||
if($bookmarkID) {
|
||||
if(empty($bookmarks)) $bookmarks = $this->getBookmarks();
|
||||
$bookmark = isset($bookmarks[$bookmarkID]) ? $bookmarks[$bookmarkID] : array();
|
||||
if(empty($bookmark)) $bookmarkID = 0;
|
||||
$bookmark = $this->bookmarks->getBookmark($bookmarkID);
|
||||
if(!$bookmark) throw new WireException("Unknown bookmark");
|
||||
if(!$this->bookmarks->isBookmarkEditable($bookmark)) throw new WirePermissionException('Bookmark is not editable');
|
||||
$fieldset->label = $this->_('Edit Bookmark');
|
||||
} else {
|
||||
$bookmark = array();
|
||||
$fieldset->label = $this->_('Add New Bookmark');
|
||||
$fieldset->description = $this->_('Creates a new bookmark matching your current filters, columns and order.');
|
||||
}
|
||||
|
||||
$fieldset->icon = $bookmarkID ? 'bookmark-o' : 'plus-circle';
|
||||
if(!$bookmarkID) $fieldset->description = $this->_('Creates a new bookmark matching your current filters, columns and order.');
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldText');
|
||||
$f->attr('name', 'bookmark_title');
|
||||
$f->label = $this->_x('Title', 'bookmark-editor'); // Bookmark title
|
||||
$f->required = true;
|
||||
if($languages) $f->useLanguages = true;
|
||||
$fieldset->add($f);
|
||||
/** @var InputfieldText $titleField */
|
||||
$titleField = $this->wire('modules')->get('InputfieldText');
|
||||
$titleField->attr('name', 'bookmark_title');
|
||||
$titleField->label = $this->_x('Title', 'bookmark-editor'); // Bookmark title
|
||||
$titleField->required = true;
|
||||
if($languages) $titleField->useLanguages = true;
|
||||
$fieldset->add($titleField);
|
||||
|
||||
/** @var InputfieldText $descField */
|
||||
$descField = $this->wire('modules')->get('InputfieldText');
|
||||
$descField->attr('name', 'bookmark_desc');
|
||||
$descField->label = $this->_x('Description', 'bookmark-editor'); // Bookmark title
|
||||
if($languages) $descField->useLanguages = true;
|
||||
$fieldset->add($descField);
|
||||
|
||||
if($bookmarkID) {
|
||||
// editing existing bookmark
|
||||
$f->attr('value', $bookmark['title']);
|
||||
if($languages) foreach($languages as $language) {
|
||||
if($language->isDefault()) continue;
|
||||
$f->attr("value$language", isset($bookmark["title$language"]) ? $bookmark["title$language"] : "");
|
||||
$titleField->attr('value', $bookmark['title']);
|
||||
$descField->attr('value', $bookmark['desc']);
|
||||
|
||||
if($languages) {
|
||||
foreach($languages as $language) {
|
||||
if($language->isDefault()) continue;
|
||||
$titleField->attr("value$language", isset($bookmark["title$language"]) ? $bookmark["title$language"] : "");
|
||||
$descField->attr("value$language", isset($bookmark["desc$language"]) ? $bookmark["desc$language"] : "");
|
||||
}
|
||||
}
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldSelector');
|
||||
$f->attr('name', 'bookmark_selector');
|
||||
$f->label = $this->_x('What pages should this bookmark show?', 'bookmark-editor');
|
||||
$selector = $bookmark['selector'];
|
||||
if($bookmark['sort']) $selector .= ", sort=$bookmark[sort]";
|
||||
if($this->lister->initSelector && strpos($selector, $this->lister->initSelector) !== false) {
|
||||
$selector = str_replace($this->lister->initSelector, '', $selector); // ensure that $selector does not contain initSelector
|
||||
if($this->user->isSuperuser()) {
|
||||
/** @var InputfieldSelector $f */
|
||||
$f = $this->wire('modules')->get('InputfieldSelector');
|
||||
$f->attr('name', 'bookmark_selector');
|
||||
$f->label = $this->_x('What pages should this bookmark show?', 'bookmark-editor');
|
||||
$selector = $bookmark['selector'];
|
||||
if($bookmark['sort']) $selector .= ", sort=$bookmark[sort]";
|
||||
if($this->lister->initSelector && strpos($selector, $this->lister->initSelector) !== false) {
|
||||
$selector = str_replace($this->lister->initSelector, '', $selector); // ensure that $selector does not contain initSelector
|
||||
}
|
||||
if($this->lister->template) $f->initTemplate = $this->lister->template;
|
||||
$default = $this->lister->className() == 'ProcessPageLister';
|
||||
$f->preview = false;
|
||||
$f->allowSystemCustomFields = true;
|
||||
$f->allowSystemTemplates = true;
|
||||
$f->allowSubfieldGroups = $default ? false : true;
|
||||
$f->allowSubselectors = $default ? false : true;
|
||||
$f->showFieldLabels = $this->lister->useColumnLabels ? 1 : 0;
|
||||
$f->initValue = $this->lister->initSelector;
|
||||
$f->attr('value', $selector);
|
||||
$fieldset->add($f);
|
||||
|
||||
$f = $this->lister->buildColumnsField();
|
||||
$f->attr('name', 'bookmark_columns');
|
||||
$f->attr('value', $bookmark['columns']);
|
||||
$f->label = $this->_x('Columns', 'bookmark-editor');
|
||||
$fieldset->add($f);
|
||||
}
|
||||
if($this->lister->template) $f->initTemplate = $this->lister->template;
|
||||
$default = $this->lister->className() == 'ProcessPageLister';
|
||||
$f->preview = false;
|
||||
$f->allowSystemCustomFields = true;
|
||||
$f->allowSystemTemplates = true;
|
||||
$f->allowSubfieldGroups = $default ? false : true;
|
||||
$f->allowSubselectors = $default ? false : true;
|
||||
$f->showFieldLabels = $this->lister->useColumnLabels ? 1 : 0;
|
||||
$f->initValue = $this->lister->initSelector;
|
||||
$f->attr('value', $selector);
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldHidden');
|
||||
$f->attr('name', 'bookmark_type');
|
||||
$f->attr('value', (int) $bookmark['type']);
|
||||
$fieldset->add($f);
|
||||
|
||||
$f = $this->lister->buildColumnsField();
|
||||
$f->attr('name', 'bookmark_columns');
|
||||
$f->attr('value', $bookmark['columns']);
|
||||
$f->label = $this->_x('Columns', 'bookmark-editor');
|
||||
} else {
|
||||
// add new bookmark
|
||||
if($this->user->isSuperuser()) {
|
||||
$f = $this->wire('modules')->get('InputfieldRadios');
|
||||
$f->attr('name', 'bookmark_type');
|
||||
$f->label = $this->_('Bookmark type');
|
||||
$f->addOption(ListerBookmarks::typeOwned, $this->_('Owned') . ' ' .
|
||||
"[span.detail] " . $this->_('(visible to me only)') . " [/span] ");
|
||||
$f->addOption(ListerBookmarks::typePublic, $this->_('Public'));
|
||||
$f->attr('value', isset($bookmark['type']) ? (int) $bookmark['type'] : ListerBookmarks::typeOwned);
|
||||
$fieldset->add($f);
|
||||
}
|
||||
}
|
||||
|
||||
if($this->user->isSuperuser()) {
|
||||
/** @var InputfieldAsmSelect $f */
|
||||
$f = $this->wire('modules')->get('InputfieldAsmSelect');
|
||||
$f->attr('name', 'bookmark_roles');
|
||||
$f->label = $this->_x('Access', 'bookmark-editor');
|
||||
$f->icon = 'key';
|
||||
$f->description = $this->_('What user roles will see this bookmark? If no user roles are selected, then all roles with permission to use this Lister can view the bookmark.');
|
||||
foreach($this->wire('roles') as $role) {
|
||||
if($role->name != 'guest') $f->addOption($role->id, $role->name);
|
||||
}
|
||||
if($bookmarkID) $f->attr('value', $bookmark['roles']);
|
||||
$f->collapsed = Inputfield::collapsedBlank;
|
||||
$f->showIf = 'bookmark_type=' . ListerBookmarks::typePublic;
|
||||
$fieldset->add($f);
|
||||
}
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldAsmSelect');
|
||||
$f->attr('name', 'bookmark_roles');
|
||||
$f->label = $this->_x('Access', 'bookmark-editor');
|
||||
$f->icon = 'key';
|
||||
$f->description = $this->_('What user roles will see this bookmark? If no user roles are selected, then all roles with permission to use this Lister can view the bookmark.');
|
||||
foreach($this->wire('roles') as $role) {
|
||||
if($role->name != 'guest') $f->addOption($role->id, $role->name);
|
||||
/** @var InputfieldCheckbox $f */
|
||||
$f = $this->wire('modules')->get('InputfieldCheckbox');
|
||||
$f->attr('name', 'bookmark_share');
|
||||
$f->label = $this->_('Allow other users to access this bookmark URL?');
|
||||
$f->description = $this->_('If you send the bookmark URL to someone else that is already logged in to the admin, they can view the bookmark if you check this box.');
|
||||
$f->notes = sprintf(
|
||||
$this->_('Shareable bookmark URL: [View](%s)'),
|
||||
$this->page->httpUrl() . str_replace($this->page->url, '', $this->bookmarks->getBookmarkUrl($bookmarkID, $this->user))
|
||||
);
|
||||
if(empty($bookmark['share'])) {
|
||||
$f->collapsed = Inputfield::collapsedYes;
|
||||
} else {
|
||||
$f->attr('checked', 'checked');
|
||||
}
|
||||
if($bookmarkID) $f->attr('value', $bookmark['roles']);
|
||||
$f->collapsed = Inputfield::collapsedBlank;
|
||||
$f->showIf = 'bookmark_type=' . ListerBookmarks::typeOwned;
|
||||
$fieldset->add($f);
|
||||
|
||||
if($bookmarkID) {
|
||||
|
||||
/** @var InputfieldAsmSelect $f */
|
||||
$f = $this->wire('modules')->get('InputfieldAsmSelect');
|
||||
$f->attr('name', 'bookmarks_sort');
|
||||
$f->label = $this->_('Bookmarks sort order');
|
||||
$f->icon = 'sort';
|
||||
$f->setAsmSelectOption('removeLabel', '');
|
||||
$value = array();
|
||||
foreach($bookmarks as $n => $b) {
|
||||
$f->addOption($n, $b['title']);
|
||||
$value[] = $n;
|
||||
$bookmarks = $bookmark['type'] == ListerBookmarks::typePublic ? $this->bookmarks->getPublicBookmarks() : $this->bookmarks->getOwnedBookmarks();
|
||||
// option for changing the order of bookmarks
|
||||
if(count($bookmarks) > 1) {
|
||||
/** @var InputfieldAsmSelect $f */
|
||||
$f = $this->wire('modules')->get('InputfieldAsmSelect');
|
||||
$f->attr('name', 'bookmarks_sort');
|
||||
$f->label = $this->_('Order');
|
||||
$f->icon = 'sort';
|
||||
$f->setAsmSelectOption('removeLabel', '');
|
||||
$value = array();
|
||||
foreach($bookmarks as $bmid => $bm) {
|
||||
$f->addOption($bmid, $bm['title']);
|
||||
$value[] = $bmid;
|
||||
}
|
||||
$f->attr('value', $value);
|
||||
$fieldset->add($f);
|
||||
}
|
||||
$f->attr('value', $value);
|
||||
$f->collapsed = Inputfield::collapsedYes;
|
||||
$fieldset->add($f);
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldCheckbox');
|
||||
$f->attr('name', 'delete_bookmark');
|
||||
$f->label = $this->_x('Delete', 'bookmark-editor');
|
||||
$f->label2 = $this->_('Delete this bookmark?');
|
||||
$f->icon = 'trash-o';
|
||||
$f->attr('value', $bookmarkID);
|
||||
$f->collapsed = Inputfield::collapsedYes;
|
||||
$fieldset->add($f);
|
||||
}
|
||||
|
||||
/** @var InputfieldSubmit $submit */
|
||||
$submit = $this->wire('modules')->get('InputfieldSubmit');
|
||||
$submit->attr('name', 'submit_bookmark');
|
||||
$submit->attr('name', 'submit_save_bookmark');
|
||||
$submit->icon = 'bookmark-o';
|
||||
$fieldset->add($submit);
|
||||
|
||||
@@ -258,21 +421,46 @@ class ProcessPageListerBookmarks extends Wire {
|
||||
* @throws WirePermissionException
|
||||
*
|
||||
*/
|
||||
public function editBookmark() {
|
||||
public function executeEditBookmark() {
|
||||
|
||||
if(!$this->wire('user')->isSuperuser()) throw new WirePermissionException("Only superuser can edit bookmarks");
|
||||
/** @var WireInput $input */
|
||||
$input = $this->wire('input');
|
||||
|
||||
if($this->wire('input')->post('bookmark_title')) return $this->saveBookmark();
|
||||
$deleteBookmarkID = $this->bookmarks->_bookmarkID($input->post('delete_bookmark'));
|
||||
if($deleteBookmarkID) {
|
||||
if($this->bookmarks->deleteBookmarkByID($deleteBookmarkID)) {
|
||||
$this->message($this->_('Deleted bookmark'));
|
||||
} else {
|
||||
$this->error($this->_('Bookmark is not deletable'));
|
||||
}
|
||||
$this->redirectToBookmarks();
|
||||
return '';
|
||||
}
|
||||
|
||||
$bookmarkID = $this->wire('input')->get->int('n');
|
||||
if($input->post('bookmark_title')) {
|
||||
return $this->executeSaveBookmark();
|
||||
}
|
||||
|
||||
$bookmarkID = $this->bookmarks->_bookmarkID($input->get('bookmark'));
|
||||
$bookmark = $this->bookmarks->getBookmark($bookmarkID);
|
||||
|
||||
if(!$bookmark) $this->redirectToBookmarks();
|
||||
if(!$this->bookmarks->isBookmarkEditable($bookmark)) throw new WirePermissionException("Bookmark not editable");
|
||||
|
||||
/** @var InputfieldForm $form */
|
||||
$form = $this->wire('modules')->get('InputfieldForm');
|
||||
$form->attr('action', './');
|
||||
|
||||
$fieldset = $this->buildBookmarkEditForm($bookmarkID);
|
||||
if($input->get('delete')) {
|
||||
$fieldset = $this->buildBookmarkDeleteForm($bookmarkID);
|
||||
$this->lister->headline($bookmark['title']);
|
||||
} else {
|
||||
$fieldset = $this->buildBookmarkEditForm($bookmarkID);
|
||||
$this->lister->headline($fieldset->label);
|
||||
}
|
||||
$form->add($fieldset);
|
||||
$this->lister->headline($fieldset->label);
|
||||
|
||||
/** @var InputfieldHidden $f */
|
||||
$f = $this->wire('modules')->get('InputfieldHidden');
|
||||
$f->attr('name', 'bookmark_id');
|
||||
$f->attr('value', $bookmarkID);
|
||||
@@ -290,30 +478,52 @@ class ProcessPageListerBookmarks extends Wire {
|
||||
* Performs redirect after saving
|
||||
*
|
||||
*/
|
||||
protected function saveBookmark() {
|
||||
protected function executeSaveBookmark() {
|
||||
|
||||
$input = $this->wire('input');
|
||||
$sanitizer = $this->wire('sanitizer');
|
||||
$page = $this->wire('page');
|
||||
$languages = $this->wire('languages');
|
||||
|
||||
$bookmarkID = $input->post->int('bookmark_id');
|
||||
$bookmarkID = $this->bookmarks->_bookmarkID($input->post('bookmark_id'));
|
||||
$bookmarkTitle = $input->post->text('bookmark_title');
|
||||
$bookmarkDesc = $input->post->text('bookmark_desc');
|
||||
|
||||
if(!$bookmarkID && empty($bookmarkTitle)) {
|
||||
$this->wire('session')->redirect('../#tab_bookmarks');
|
||||
$this->redirectToBookmarks();
|
||||
return;
|
||||
}
|
||||
|
||||
if($bookmarkID) {
|
||||
$existingBookmark = $this->bookmarks->getBookmark($bookmarkID);
|
||||
if(!$existingBookmark || !$this->bookmarks->isBookmarkEditable($existingBookmark)) {
|
||||
throw new WirePermissionException("Bookmark not editable");
|
||||
}
|
||||
} else {
|
||||
$existingBookmark = null;
|
||||
}
|
||||
|
||||
$bookmarkSort = '';
|
||||
$textOptions = array('maxLength' => 1024, 'stripTags' => false);
|
||||
$bookmarkSelector = $bookmarkID ? $input->post->text('bookmark_selector', $textOptions) : $this->lister->getSelector();
|
||||
$textOptions = array(
|
||||
'maxLength' => 1024,
|
||||
'stripTags' => false
|
||||
);
|
||||
|
||||
if($this->user->isSuperuser()) {
|
||||
$bookmarkSelector = $bookmarkID ? $input->post->text('bookmark_selector', $textOptions) : $this->lister->getSelector();
|
||||
} else {
|
||||
$bookmarkSelector = $existingBookmark ? $existingBookmark['selector'] : $this->lister->getSelector();
|
||||
}
|
||||
|
||||
if(preg_match('/\bsort=([-_.a-zA-Z]+)/', $bookmarkSelector, $matches)) $bookmarkSort = $matches[1];
|
||||
$bookmarkSelector = preg_replace('/\b(include|sort|limit)=[^,]+,?/', '', $bookmarkSelector);
|
||||
|
||||
if($this->lister->initSelector && strpos($bookmarkSelector, $this->lister->initSelector) !== false) {
|
||||
// ensure that $selector does not contain initSelector
|
||||
$bookmarkSelector = str_replace($this->lister->initSelector, '', $bookmarkSelector);
|
||||
}
|
||||
|
||||
$bookmarkSelector = str_replace(', , ', ', ', $bookmarkSelector);
|
||||
$bookmarkSelector = trim($bookmarkSelector, ', ');
|
||||
|
||||
if($bookmarkID) {
|
||||
$bookmarkColumns = $input->post('bookmark_columns');
|
||||
@@ -330,63 +540,89 @@ class ProcessPageListerBookmarks extends Wire {
|
||||
$bookmarkColumns = $this->lister->columns;
|
||||
}
|
||||
|
||||
$bookmark = array(
|
||||
$bookmark = $this->bookmarks->_bookmark(array(
|
||||
'id' => $bookmarkID,
|
||||
'title' => $bookmarkTitle,
|
||||
'selector' => trim($bookmarkSelector, ", "),
|
||||
'desc' => $bookmarkDesc,
|
||||
'selector' => $bookmarkSelector,
|
||||
'columns' => $bookmarkColumns,
|
||||
'sort' => $bookmarkSort,
|
||||
'roles' => $input->post->intArray('bookmark_roles')
|
||||
);
|
||||
'share' => $input->post('bookmark_share') ? true : false
|
||||
));
|
||||
|
||||
$languages = $this->wire('languages');
|
||||
if($languages) foreach($languages as $language) {
|
||||
if($language->isDefault()) continue;
|
||||
$bookmark["title$language"] = $input->post->text("bookmark_title__$language");
|
||||
}
|
||||
|
||||
$data = $this->wire('modules')->getModuleConfigData('ProcessPageLister');
|
||||
$_bookmarks = isset($data['bookmarks']) ? $data['bookmarks'] : array();
|
||||
|
||||
foreach($_bookmarks as $pageID => $bookmarks) {
|
||||
// remove bookmarks for Lister pages that no longer exist
|
||||
$pageID = (int) ltrim($pageID, '_');
|
||||
if($pageID == $page->id) continue;
|
||||
if(!$this->wire('pages')->get($pageID)->id) unset($_bookmarks[$pageID]);
|
||||
}
|
||||
|
||||
$bookmarks = isset($_bookmarks["_$page->id"]) ? $_bookmarks["_$page->id"] : array();
|
||||
|
||||
if($bookmarkID) {
|
||||
$n = $bookmarkID;
|
||||
if($this->user->isSuperuser()) {
|
||||
$bookmark['type'] = $input->post->int('bookmark_type');
|
||||
$bookmark['roles'] = $input->post->intArray('bookmark_roles');
|
||||
} else {
|
||||
$n = time();
|
||||
while(isset($bookmarks[$n])) $n++;
|
||||
$bookmark['type'] = ListerBookmarks::typeOwned;
|
||||
$bookmark['roles'] = array();
|
||||
}
|
||||
|
||||
$bookmarks["_$n"] = $bookmark;
|
||||
if($languages) {
|
||||
foreach($languages as $language) {
|
||||
if($language->isDefault()) continue;
|
||||
$bookmark["title$language"] = $input->post->text("bookmark_title__$language");
|
||||
$bookmark["desc$language"] = $input->post->text("bookmark_desc__$language");
|
||||
}
|
||||
}
|
||||
|
||||
if($bookmark['type'] == ListerBookmarks::typeOwned) {
|
||||
$bookmarks = $this->bookmarks->getOwnedBookmarks();
|
||||
} else {
|
||||
$bookmarks = $this->bookmarks->getPublicBookmarks();
|
||||
}
|
||||
|
||||
$typePrefix = $this->bookmarks->typePrefix($bookmark['type']);
|
||||
if(!$bookmarkID) $bookmarkID = $typePrefix . time(); // new bookmark
|
||||
$bookmarks[$bookmarkID] = $bookmark;
|
||||
|
||||
// update sort order of all bookmarks
|
||||
if($input->post->bookmarks_sort) {
|
||||
if($input->post('bookmarks_sort')) {
|
||||
$sorted = array();
|
||||
foreach($input->post->intArray('bookmarks_sort') as $bmid) {
|
||||
$bm = $bookmarks["_$bmid"];
|
||||
$sorted["_$bmid"] = $bm;
|
||||
foreach($input->post->array('bookmarks_sort') as $bmid) {
|
||||
$bmid = $this->bookmarks->_bookmarkID($bmid);
|
||||
if(!isset($bookmarks[$bmid])) continue;
|
||||
$bm = $bookmarks[$bmid];
|
||||
$sorted[$bmid] = $bm;
|
||||
}
|
||||
$bookmarks = $sorted;
|
||||
}
|
||||
|
||||
if($bookmarkID && $input->post('delete_bookmark') == $bookmarkID) {
|
||||
unset($bookmarks["_$n"]);
|
||||
$this->message(sprintf($this->_('Deleted bookmark: %s'), $bookmarkTitle));
|
||||
$bookmarkID = 0;
|
||||
if($bookmark['type'] == ListerBookmarks::typeOwned) {
|
||||
$this->bookmarks->saveOwnedBookmarks($bookmarks);
|
||||
} else {
|
||||
$this->message(sprintf($this->_('Saved bookmark: %s'), $bookmarkTitle));
|
||||
$this->bookmarks->savePublicBookmarks($bookmarks);
|
||||
}
|
||||
|
||||
$_bookmarks["_$page->id"] = $bookmarks;
|
||||
$data['bookmarks'] = $_bookmarks;
|
||||
$this->redirectToBookmarks($bookmarkID);
|
||||
}
|
||||
|
||||
$this->wire('modules')->saveModuleConfigData('ProcessPageLister', $data);
|
||||
$this->wire('session')->redirect("../?bookmark=$bookmarkID#tab_bookmarks");
|
||||
protected function redirectToBookmarks($bookmarkID = '') {
|
||||
$url = $this->page->url;
|
||||
if($bookmarkID) {
|
||||
$this->wire('session')->redirect($url . "?bookmark=$bookmarkID#tab_bookmarks");
|
||||
} else {
|
||||
$this->wire('session')->redirect($url . '#tab_bookmarks');
|
||||
}
|
||||
}
|
||||
|
||||
public function _bookmark(array $bookmark = array()) {
|
||||
return $this->bookmarks->_bookmark($bookmark);
|
||||
}
|
||||
|
||||
public function _bookmarkID($bookmarkID) {
|
||||
return $this->bookmarks->_bookmarkID($bookmarkID);
|
||||
}
|
||||
|
||||
public function getBookmark($bookmarkID, $type = null) {
|
||||
return $this->bookmarks->getBookmark($bookmarkID, $type);
|
||||
}
|
||||
|
||||
public function getBookmarks() {
|
||||
return $this->bookmarks->getBookmarks();
|
||||
}
|
||||
|
||||
public function isBookmarkViewable($bookmark) {
|
||||
return $this->bookmarks->isBookmarkViewable($bookmark);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user