1
0
mirror of https://github.com/e107inc/e107.git synced 2025-07-31 20:00:37 +02:00

Private Message: Issue #1423, #1434 - v2.x fixes/updates. Improved user-file upload handling.

This commit is contained in:
Cameron
2016-03-30 19:10:00 -07:00
parent 324be8ebdc
commit 2e067dfdf7
18 changed files with 745 additions and 764 deletions

View File

@@ -813,7 +813,7 @@ class e_file
/**
* File retrieval function. by Cam.
* @param $file actual path or {e_xxxx} path to file.
* @param $file string actual path or {e_xxxx} path to file.
*
*/
function send($file)
@@ -930,6 +930,36 @@ class e_file
}
/**
* Return a user specific file directory for the current plugin with the option to create one if it does not exist.
* @param $baseDir
* @param $user - user_id
* @param bool|false $create
* @return bool|string
*/
public function getUserDir($user, $create = false, $subDir = null)
{
$user = intval($user);
$tp = e107::getParser();
$baseDir = e_MEDIA.'plugins/'.e_CURRENT_PLUGIN.'/';
if(!empty($subDir))
{
$baseDir .= rtrim($subDir,'/').'/';
}
$baseDir .= ($user) ? "user_". $tp->leadingZeros($user, 6) : "anon";
if($create == true && !is_dir($baseDir))
{
mkdir($baseDir, 0755, true); // recursively
}
$baseDir .= "/";
return $baseDir;
}
/**
@@ -1033,11 +1063,89 @@ class e_file
/**
* File-class wrapper for upload handler. (Preferred for v2.x)
* Process files uploaded in a form post. ie. $_FILES.
* Routine processes the array of uploaded files according to both specific options set by the caller,
* and system options configured by the main admin.
*
* @param string $uploaddir Target directory (checked that it exists, but path not otherwise changed)
*
* @param string $fileinfo Determines any special handling of file name (combines previous $fileinfo and $avatar parameters):
* FALSE - default option; no processing
* @param string $fileinfo = 'attachment+extra_text' Indicates an attachment (related to forum post or PM), and specifies some optional text which is
* incorporated into the final file name (the original $fileinfo parameter).
* @param string $fileinfo = 'prefix+extra_text' - indicates an attachment or file, and specifies some optional text which is prefixed to the file name
* @param string $fileinfo = 'unique'
* - if the proposed destination file doesn't exist, saved under given name
* - if the proposed destination file does exist, prepends time() to the file name to make it unique
* @param string $fileinfo = 'avatar'
* - indicates an avatar is being uploaded (not used - options must be set elsewhere)
*
* @param array $options An array of supplementary options, all of which will be given appropriate defaults if not defined:
* @param $options['filetypes'] Name of file containing list of valid file types
* - Always looks in the admin directory
* - defaults to e_ADMIN.filetypes.xml, else e_ADMIN.admin_filetypes.php for admins (if file exists), otherwise e_ADMIN.filetypes.php for users.
* - FALSE disables this option (which implies that 'extra_file_types' is used)
* @param string $options['file_mask'] Comma-separated list of file types which if defined limits the allowed file types to those which are in both this list and the
* file specified by the 'filetypes' option. Enables restriction to, for example, image files.
* @param bool $options['extra_file_types'] - if is FALSE or undefined, rejects totally unknown file extensions (even if in $options['filetypes'] file).
* if TRUE, accepts totally unknown file extensions which are in $options['filetypes'] file.
* otherwise specifies a comma-separated list of additional permitted file extensions
* @param int $options['final_chmod'] - chmod() to be applied to uploaded files (0644 default) (This routine expects an integer value, so watch formatting/decoding - its normally
* specified in octal. Typically use intval($permissions,8) to convert)
* @param int $options['max_upload_size'] - maximum size of uploaded files in bytes, or as a string with a 'multiplier' letter (e.g. 16M) at the end.
* - otherwise uses $pref['upload_maxfilesize'] if set
* - overriding limit of the smaller of 'post_max_size' and 'upload_max_size' if set in php.ini
* (Note: other parts of E107 don't understand strings with a multiplier letter yet)
* @param string $options['file_array_name'] - the name of the 'input' array - defaults to file_userfile[] - otherwise as set.
* @param int $options['max_file_count'] - maximum number of files which can be uploaded - default is 'unlimited' if this is zero or not set.
* @param bool $options['overwrite'] - if TRUE, existing file of the same name is overwritten; otherwise returns 'duplicate file' error (default FALSE)
* @param int $options['save_to_db'] - [obsolete] storage type - if set and TRUE, uploaded files were saved in the database (rather than as flat files)
*
* @return boolean|array
* Returns FALSE if the upload directory doesn't exist, or various other errors occurred which restrict the amount of meaningful information.
* Returns an array, with one set of entries per uploaded file, regardless of whether saved or
* discarded (not all fields always present) - $c is array index:
* $uploaded[$c]['name'] - file name - as saved to disc
* $uploaded[$c]['rawname'] - original file name, prior to any addition of identifiers etc (useful for display purposes)
* $uploaded[$c]['type'] - mime type (if set - as sent by browser)
* $uploaded[$c]['size'] - size in bytes (should be zero if error)
* $uploaded[$c]['error'] - numeric error code (zero = OK)
* $uploaded[$c]['index'] - if upload successful, the index position from the file_userfile[] array - usually numeric, but may be alphanumeric if coded
* $uploaded[$c]['message'] - text of displayed message relating to file
* $uploaded[$c]['line'] - only if an error occurred, has line number (from __LINE__)
* $uploaded[$c]['file'] - only if an error occurred, has file name (from __FILE__)
*
* On exit, uploaded files should all have been removed from the temporary directory.
* No messages displayed - its caller's responsibility to handle errors and display info to
* user (or can use handle_upload_messages() from this module)
*
* Details of uploaded files are in $_FILES['file_userfile'] (or other array name as set) on entry.
* Elements passed (from PHP) relating to each file:
* ['name'] - the original name
* ['type'] - mime type (if provided - not checked by PHP)
* ['size'] - file size in bytes
* ['tmp_name'] - temporary file name on server
* ['error'] - error code. 0 = 'good'. 1..4 main others, although up to 8 defined for later PHP versions
* Files stored in server's temporary directory, unless another set
*/
public function getUploaded($uploaddir, $fileinfo = false, $options = null)
{
require_once(e_HANDLER."upload_handler.php");
return process_uploaded_files($uploaddir, $fileinfo, $options);
if($uploaddir == e_UPLOAD || $uploaddir == e_TEMP)
{
$path = $uploaddir;
}
elseif(defined('e_CURRENT_PLUGIN'))
{
$path = $this->getUserDir(USERID, true, str_replace("../",'',$uploaddir)); // .$this->get;
}
else
{
return false;
}
return process_uploaded_files($path, $fileinfo, $options);
}

View File

@@ -560,7 +560,7 @@ class e_db_mysql
}
else
{
echo "what happened to db_debug??!!<br />";
// echo "what happened to db_debug??!!<br />";
}
}

View File

@@ -455,7 +455,7 @@ function handle_upload_messages(&$upload_array, $errors_only = TRUE, $use_handle
* This is the 'legacy' interface, which handles various special cases etc.
* It was the only option in E107 0.7.8 and earlier, and is still used in some places in core.
* It also attempts to return in the same way as the original, especially when any errors occur
*
* @deprecated
* @param string $uploaddir - target directory for file. Defaults to e_FILE/public
* @param boolean|string $avatar - sets the 'type' or destination of the file:
* FALSE - its a 'general' file
@@ -473,7 +473,14 @@ function handle_upload_messages(&$upload_array, $errors_only = TRUE, $use_handle
* otherwise returns an array with per-file error codes as appropriate.
* On exit, F_MESSAGE is defined with the success/failure message(s) that have been displayed - one file per line
*/
/**
* @Deprecated use e107::getFile()->getUploaded();
* @param $uploaddir
* @param bool|false $avatar
* @param string $fileinfo
* @param string $overwrite
* @return array|bool
*/
function file_upload($uploaddir, $avatar = FALSE, $fileinfo = "", $overwrite = "")
{
$admin_log = e107::getAdminLog();

View File

@@ -42,10 +42,11 @@ class user_select
break;
}
$text = "<select class='tbox' id='user' name='user' onchange=\"uc_switch('class')\">";
$text = "<select class='tbox form-control' id='user' name='user' onchange=\"uc_switch('class')\">";
$text .= "<option value=''>".US_LAN_1."</option>";
$sql -> db_Select("user", "user_name", $where." ORDER BY user_name");
while ($row = $sql -> db_Fetch()) {
$sql ->select("user", "user_name", $where." ORDER BY user_name");
while ($row = $sql ->fetch())
{
$text .= "<option value='".$row['user_name']."'>".$row['user_name']."</option>";
}
$text .= "</select>";
@@ -134,7 +135,7 @@ class user_select
}
else
{
$text .= "<input class='tbox' type='text' name='".$form_id."' id='".$form_id."' size='25' maxlength='30' value='".$tp -> post_toForm($user_value)."'>&nbsp;";
$text .= "<input class='form-control tbox' type='text' name='".$form_id."' id='".$form_id."' size='25' maxlength='30' value='".$tp -> post_toForm($user_value)."'>&nbsp;";
}
$text .= "<img src='".e_IMAGE_ABS."generic/user_select.png'
style='width: 16px; height: 16px; vertical-align: top' alt='".US_LAN_4."...'

View File

@@ -0,0 +1,124 @@
<?php
/**
* e107 website system
*
* Copyright (C) 2008-2016 e107 Inc (e107.org)
* Released under the terms and conditions of the
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt)
*
*/
if (!defined('e107_INIT')) { exit; }
class pm_shortcodes extends e_shortcode
{
private $pm = null;
private $prefs = null;
function __construct()
{
include_lan(e_PLUGIN.'pm/languages/'.e_LANGUAGE.'.php');
require_once(e_PLUGIN."pm/pm_func.php");
$this->pm = new pmbox_manager;
$this->prefs = $this->pm->prefs();
}
function sc_pm_nav($parm='')
{
$tp = e107::getParser();
if(!check_class($this->prefs['pm_class']))
{
return null;
}
$mbox = $this->pm->pm_getInfo('inbox');
if(!empty($mbox['inbox']['new']))
{
$count = "<span class='label label-warning'>".$mbox['inbox']['new']."</span>";
$icon = $tp->toGlyph('fa-envelope');
}
else
{
$icon = $tp->toGlyph('fa-envelope-o');
$count = '';
}
$urlInbox = e107::url('pm','index','', array('query'=>array('mode'=>'inbox')));
$urlOutbox = e107::url('pm','index','', array('query'=>array('mode'=>'outbox')));
$urlCompose = e107::url('pm','index','', array('query'=>array('mode'=>'send')));
return '<a class="dropdown-toggle" data-toggle="dropdown" href="#">'.$icon.$count.'</a>
<ul class="dropdown-menu">
<li>
<a href="'.$urlInbox.'">'.LAN_PM_25.'</a>
<a href="'.$urlOutbox.'">'.LAN_PM_26.'</a>
<a href="'.$urlCompose.'">'.LAN_PM_35.'</a>
</li>
</ul>';
}
function sc_sendpm($parm='')
{
// global $sysprefs, $pm_prefs;
// $pm_prefs = $sysprefs->getArray("pm_prefs");
$pm_prefs = e107::getPlugPref('pm');
$url = e107::url('pm','index').'?send.'.$parm;
if(check_class($pm_prefs['pm_class']))
{
if(deftrue('FONTAWESOME') && deftrue('BOOTSTRAP'))
{
$img = e107::getParser()->toGlyph('fa-paper-plane','');
return "<a class='btn btn-sm btn-default' href='".$url ."'>{$img} ".LAN_PM_35."</a>";
}
if(file_exists(THEME.'forum/pm.png'))
{
$img = "<img src='".THEME_ABS."forum/pm.png' alt='".LAN_PM."' title='".LAN_PM."' style='border:0' />";
}
else
{
$img = "<img src='".e_PLUGIN_ABS."pm/images/pm.png' alt='".LAN_PM."' title='".LAN_PM."' style='border:0' />";
}
return "<a href='".$url ."'>{$img}</a>";
}
else
{
return null;
}
}
}

61
e107_plugins/pm/e_url.php Normal file
View File

@@ -0,0 +1,61 @@
<?php
/*
* e107 Bootstrap CMS
*
* Copyright (C) 2008-2015 e107 Inc (e107.org)
* Released under the terms and conditions of the
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt)
*
* IMPORTANT: Make sure the redirect script uses the following code to load class2.php:
*
* if (!defined('e107_INIT'))
* {
* require_once("../../class2.php");
* }
*
*/
if (!defined('e107_INIT')) { exit; }
// v2.x Standard - Simple mod-rewrite module.
class pm_url // plugin-folder + '_url'
{
function config()
{
$config = array();
/*
$config['inbox'] = array(
'regex' => '^forum/rules/?',
'sef' => 'forum/rules',
'redirect' => '{e_PLUGIN}forum/forum.php?f=rules',
);
$config['outbox'] = array(
'regex' => '^forum/stats/?',
'sef' => 'forum/stats',
'redirect' => '{e_PLUGIN}forum/forum_stats.php',
);
$config['compose'] = array(
'regex' => '^forum/track/?',
'sef' => 'forum/track',
'redirect' => '{e_PLUGIN}forum/forum.php?f=track',
);*/
$config['index'] = array(
'regex' => '^pm/?(.*)', // matched against url, and if true, redirected to 'redirect' below.
'sef' => 'pm', // used by e107::url(); to create a url from the db table.
'redirect' => '{e_PLUGIN}pm/pm.php$1', // file-path of what to load when the regex returns true.
);
return $config;
}
}

7
e107_plugins/pm/pm.css Normal file
View File

@@ -0,0 +1,7 @@
tr.pm-unread { font-weight: bold }
.pm-show h3 { margin-top:5px }
.pm-show h3 small { margin-top:5px }
div.pm-message { min-height:150px }

View File

@@ -20,7 +20,10 @@
$retrieve_prefs[] = 'pm_prefs';
require_once('../../class2.php');
if (!defined('e107_INIT'))
{
require_once("../../class2.php");
}
if (!e107::isInstalled('pm'))
@@ -34,19 +37,44 @@ if(vartrue($_POST['keyword']))
pm_user_lookup();
}
e107::css('pm','pm.css');
require_once(e_PLUGIN.'pm/pm_class.php');
require_once(e_PLUGIN.'pm/pm_func.php');
include_lan(e_PLUGIN.'pm/languages/'.e_LANGUAGE.'.php');
e107::getScParser();
require_once(e_PLUGIN.'pm/pm_shortcodes.php');
// require_once(e_PLUGIN.'pm/shortcodes/batch/pm_shortcodes.php');
if(!defined('ATTACHMENT_ICON'))
{
if(deftrue('BOOTSTRAP') && deftrue('FONTAWESOME'))
{
define('ATTACHMENT_ICON', $tp->toGlyph('fa-paperclip'));
}
else
{
define('ATTACHMENT_ICON', "<img src='".e_PLUGIN."pm/images/attach.png' alt='' />");
}
}
if(deftrue('BOOTSTRAP') && deftrue('FONTAWESOME'))
{
define('PM_DELETE_ICON', $tp->toGlyph('fa-trash'));
}
else
{
define("PM_DELETE_ICON","<img src='".e_PLUGIN_ABS."pm/images/mail_delete.png' alt='".LAN_DELETE."' class='icon S16' />");
}
$qs = explode('.', e_QUERY);
$action = varset($qs[0],'inbox');
if (!$action) $action = 'inbox';
if(!empty($_GET['mode']))
{
$action = $tp->filter($_GET['mode']);
}
if($action == 'textarea' || $action == 'input')
{
if($qs[1] == 'pm_to') {
@@ -138,7 +166,7 @@ class pm_extended extends private_message
$enc = (check_class($this->pmPrefs['attach_class']) ? "enctype='multipart/form-data'" : '');
// setScVar('pm_handler_shortcodes','pmInfo', $pm_info);
$sc = e107::getScBatch('pm',TRUE);
$sc = e107::getScBatch('pm',true, true);
$sc->setVars($pm_info);
$PM_SEND_PM = $this->updateTemplate($PM_SEND_PM);
@@ -170,7 +198,7 @@ class pm_extended extends private_message
// setScVar('pm_handler_shortcodes', 'pmNextPrev', array('start' => $start, 'total' => $pmlist['total_messages']));
$sc = e107::getScBatch('pm',TRUE);
$sc = e107::getScBatch('pm',true, 'pm');
$sc->pmNextPrev = array('start' => $start, 'total' => $pmlist['total_messages']);
@@ -179,7 +207,7 @@ class pm_extended extends private_message
$PM_INBOX_EMPTY = $this->updateTemplate($PM_INBOX_EMPTY);
$PM_INBOX_FOOTER = $this->updateTemplate($PM_INBOX_FOOTER);
$txt = "<form method='post' action='".e_SELF."?".e_QUERY."'>";
$txt = "<form method='post' action='".e_REQUEST_SELF."?".e_QUERY."'>";
$txt .= $tp->parseTemplate($PM_INBOX_HEADER, true, $sc);
if($pmlist['total_messages'])
@@ -218,7 +246,7 @@ class pm_extended extends private_message
$pmlist = $this->pm_get_outbox(USERID, $start, $this->pmPrefs['perpage']);
// setScVar('pm_handler_shortcodes', 'pmNextPrev', array('start' => $start, 'total' => $pmlist['total_messages']));
$sc = e107::getScBatch('pm',TRUE);
$sc = e107::getScBatch('pm', true, 'pm');
$sc->pmNextPrev = array('start' => $start, 'total' => $pmlist['total_messages']);
$PM_OUTBOX_HEADER = $this->updateTemplate($PM_OUTBOX_HEADER);
@@ -264,15 +292,14 @@ class pm_extended extends private_message
include_once(is_readable($tpl_file) ? $tpl_file : e_PLUGIN.'pm/pm_template.php');
$pm_info = $this->pm_get($pmid);
// setScVar('pm_handler_shortcodes','pmInfo', $pm_info);
$sc = e107::getScBatch('pm',TRUE);
$sc = e107::getScBatch('pm',true, 'pm');
$sc->setVars($pm_info);
if($pm_info['pm_to'] != USERID && $pm_info['pm_from'] != USERID)
{
$ns->tablerender(LAN_PM, LAN_PM_60);
require_once(FOOTERF);
exit;
return;
}
if($pm_info['pm_read'] == 0 && $pm_info['pm_to'] == USERID)
@@ -282,11 +309,22 @@ class pm_extended extends private_message
$this->pm_mark_read($pmid, $pm_info);
}
$sc->pmMode = $comeFrom;
$PM_SHOW = $this->updateTemplate($PM_SHOW);
$txt = e107::getParser()->parseTemplate($PM_SHOW, true, $sc);
$ns->tablerender(LAN_PM, $txt);
if($comeFrom == 'outbox')
{
$bread = array('text'=> LAN_PM_26, 'url'=>e107::url('pm','index').'?mode=outbox');
}
else
{
$bread = array('text'=> LAN_PM_25, 'url'=>e107::url('pm','index').'?mode=inbox');
}
$ns->tablerender(LAN_PM, $this->breadcrumb($bread ,'#'.$pmid).$txt);
if (!$comeFrom)
{
@@ -296,11 +334,16 @@ class pm_extended extends private_message
// Need to show inbox or outbox from start
if ($comeFrom == 'outbox')
{ // Show Outbox
$ns->tablerender(LAN_PM." - ".LAN_PM_26, $this->show_outbox(), 'PM');
$caption = '';
if(!deftrue('BOOTSTRAP')){ $caption .= LAN_PM." - ".LAN_PM_26; }
$ns->tablerender($caption, $this->show_outbox(), 'PM');
}
else
{ // Show Inbox
$ns->tablerender(LAN_PM.' - '.LAN_PM_25, $this->show_inbox(), 'PM');
$caption = '';
if(!deftrue('BOOTSTRAP')){ $caption .= LAN_PM." - ".LAN_PM_25; }
$ns->tablerender($caption, $this->show_inbox(), 'PM');
}
}
@@ -318,7 +361,7 @@ class pm_extended extends private_message
include(is_readable($tpl_file) ? $tpl_file : e_PLUGIN.'pm/pm_template.php');
$pmBlocks = $this->block_get_user(); // TODO - handle pagination, maybe (is it likely to be necessary?)
$sc = e107::getScBatch('pm',TRUE);
$sc = e107::getScBatch('pm',TRUE, 'pm');
$sc->pmBlocks = $pmBlocks;
$PM_BLOCKED_HEADER = $this->updateTemplate($PM_BLOCKED_HEADER);
@@ -394,10 +437,12 @@ class pm_extended extends private_message
$to_array[$k] = trim($v);
}
$to_array = array_unique($to_array);
if(count($to_array) == 1)
{
$_POST['pm_to'] = $to_array[0];
}
if(check_class($this->pmPrefs['multi_class']) && count($to_array) > 1)
{
foreach($to_array as $to)
@@ -436,8 +481,17 @@ class pm_extended extends private_message
unset($_POST['receipt']);
}
}
$totalsize = strlen($_POST['pm_message']);
$maxsize = intval($this->pmPrefs['attach_size']) * 1024;
foreach(array_keys($_FILES['file_userfile']['size']) as $fid)
{
if($maxsize > 0 && $_FILES['file_userfile']['size'][$fid] > $maxsize)
@@ -466,6 +520,29 @@ class pm_extended extends private_message
}
}
if(check_class($this->pmPrefs['attach_class']))
{
$_POST['uploaded'] = $this->processAttachments();
foreach($_POST['uploaded'] as $var)
{
if(!empty($var['message']))
{
$msg .= $var['message']."<br />";
}
}
}
else
{
$msg .= LAN_PM_23.'<br />';
unset($_POST['uploaded']);
}
/*
if($_FILES['file_userfile']['name'][0])
{
if(check_class($this->pmPrefs['attach_class']))
@@ -485,14 +562,60 @@ class pm_extended extends private_message
unset($_POST['uploaded']);
}
}
*/
$_POST['from_id'] = USERID;
return $msg.$this->add($_POST);
}
}
function processAttachments()
{
$randnum = rand(1000, 9999);
$type = 'attachment+'.$randnum.'_';
return e107::getFile()->getUploaded("attachments",$type, array('max_file_count'=>3));
}
function breadcrumb($type='',$other)
{
if(!deftrue('BOOTSTRAP'))
{
return null;
}
$array = array();
$array[0] = array('text'=>LAN_PM, 'url'=>e107::url('pm','index'));
if(is_string($type))
{
$array[1] = array('text'=>$type, 'url'=>null);
}
elseif(is_array($type))
{
$array[1] = $type;
}
if($other)
{
$array[2] = array('text'=>$other, 'url'=>null);
}
return e107::getForm()->breadcrumb($array);
}
}
/**
* Look up users matching a keyword, output a list of those found
* Direct echo
@@ -663,7 +786,7 @@ if($message != '')
switch ($action)
{
case 'send' :
$ns->tablerender(LAN_PM, $mes->render() . $pm->show_send($pm_proc_id));
$ns->tablerender(LAN_PM, $pm->breadcrumb(LAN_PM_35). $mes->render() . $pm->show_send($pm_proc_id));
break;
case 'reply' :
@@ -672,33 +795,41 @@ switch ($action)
{
if($pm_info['pm_to'] != USERID)
{
$ns->tablerender(LAN_PM, $mes->render() . LAN_PM_56);
$ns->tablerender(LAN_PM, $pm->breadcrumb(LAN_PM_55).$mes->render() . LAN_PM_56);
}
else
{
$ns->tablerender(LAN_PM, $mes->render() . $pm->show_send($pm_info));
$ns->tablerender(LAN_PM, $pm->breadcrumb(LAN_PM_55). $mes->render() . $pm->show_send($pm_info));
}
}
else
{
$ns->tablerender(LAN_PM, $mes->render() . LAN_PM_57);
$ns->tablerender(LAN_PM, $pm->breadcrumb(LAN_PM_55). $mes->render() . LAN_PM_57);
}
break;
case 'inbox' :
$ns->tablerender(LAN_PM.' - '.LAN_PM_25, $mes->render() . $pm->show_inbox($pm_proc_id), 'PM');
$caption = LAN_PM;
if(!deftrue('BOOTSTRAP')){ $caption .= ' - '.LAN_PM_25; }
$ns->tablerender($caption, $pm->breadcrumb(LAN_PM_25). $mes->render() . $pm->show_inbox($pm_proc_id), 'PM');
break;
case 'outbox' :
$ns->tablerender(LAN_PM.' - '.LAN_PM_26, $mes->render() . $pm->show_outbox($pm_proc_id), 'PM');
$caption = LAN_PM;
if(!deftrue('BOOTSTRAP')){ $caption .= ' - '.LAN_PM_26; }
$ns->tablerender($caption, $pm->breadcrumb(LAN_PM_26).$mes->render() . $pm->show_outbox($pm_proc_id), 'PM');
break;
case 'show' :
$pm->show_pm($pm_proc_id, $pmSource);
break;
case 'blocked' :
$ns->tablerender(LAN_PM.' - '.LAN_PM_66, $mes->render() . $pm->showBlocked($pm_proc_id), 'PM');
$caption = LAN_PM;
if(!deftrue('BOOTSTRAP')){ $caption .= ' - '.LAN_PM_66; }
$ns->tablerender($caption, $pm->breadcrumb('blocked').$mes->render() . $pm->showBlocked($pm_proc_id), 'PM');
break;
}

View File

@@ -19,6 +19,13 @@ class private_message
protected $e107;
protected $pmPrefs;
public function prefs()
{
return $this->pmPrefs;
}
/**
* Constructor
*
@@ -128,6 +135,7 @@ class private_message
{ // Send triggered by user - may be immediate or bulk dependent on number of recipients
$vars['options'] = '';
if(isset($vars['receipt']) && $vars['receipt']) {$pm_options .= '+rr+'; }
if(isset($vars['uploaded']))
{
foreach($vars['uploaded'] as $u)
@@ -163,6 +171,9 @@ class private_message
'pm_option' => $pm_options, /* Options associated with PM - '+rr' for read receipt */
'pm_size' => $pmsize
);
print_a($info);
print_a($vars);
}
if(isset($vars['to_userclass']) || isset($vars['to_array']))
@@ -333,12 +344,12 @@ class private_message
/**
* Convinient url assembling shortcut
*/
*//*
public function url($action, $params = array(), $options = array())
{
if(strpos($action, '/') === false) $action = 'view/'.$action;
e107::getUrl()->create('pm/'.$action, $params, $options);
}
}*/
/**
* Send an email to notify of a PM
@@ -354,8 +365,10 @@ class private_message
{
require_once(e_HANDLER.'mail.php');
$subject = LAN_PM_100.SITENAME;
// $pmlink = $this->url('show', 'id='.$pmid, 'full=1&encode=0'); //TODO broken - replace with e_url.php configuration.
$pmlink = SITEURLBASE.e_PLUGIN_ABS."pm/pm.php?show.".$pmid;
// $pmlink = SITEURLBASE.e_PLUGIN_ABS."pm/pm.php?show.".$pmid;
$pmlink = e107::url('pm','index').'?show.'.$pmid;
$txt = LAN_PM_101.SITENAME."\n\n";
$txt .= LAN_PM_102.USERNAME."\n";
$txt .= LAN_PM_103.$pmInfo['pm_subject']."\n";
@@ -600,11 +613,13 @@ class private_message
ORDER BY pm.pm_sent DESC
LIMIT ".$from.", ".$limit."
";
if($sql->gen($qry))
{
$total_messages = $sql->total_results; // Total number of messages
$total_messages = $sql->foundRows(); // Total number of messages
$ret['messages'] = $sql->db_getList();
}
$ret['total_messages'] = $total_messages; // Should always be defined
return $ret;
}
@@ -653,28 +668,56 @@ class private_message
*
* @return none
*
* @todo Can we use core send routine?
*/
function send_file($pmid, $filenum)
{
$pm_info = $this->pm_get($pmid);
$attachments = explode(chr(0), $pm_info['pm_attachments']);
if(!isset($attachments[$filenum]))
{
return FALSE;
return false;
}
$fname = $attachments[$filenum];
list($timestamp, $fromid, $rand, $file) = explode("_", $fname, 4);
$filename = getcwd()."/attachments/{$fname}";
$filename = false; // getcwd()."/attachments/{$fname}";
$pathList = array();
$pathList[] = e_PLUGIN."pm/attachments/"; // getcwd()."/attachments/"; // legacy path.
$pathList[] = e107::getFile()->getUserDir($fromid, false, 'attachments'); // new media path.
foreach($pathList as $path)
{
$tPath = $path.$fname;
if(is_file($tPath))
{
$filename = $tPath;
break;
}
}
if(empty($filename) || !is_file($filename))
{
return false;
}
if($fromid != $pm_info['pm_from'])
{
return FALSE;
}
if(!is_file($filename))
{
return FALSE;
return false;
}
// e107::getFile()->send($filename); // limited to Media and system folders. Won't work for legacy plugin path.
// exit;
@set_time_limit(10 * 60);
@e107_ini_set("max_execution_time", 10 * 60);
while (@ob_end_clean()); // kill all output buffering else it eats server resources
@@ -721,6 +764,12 @@ class private_message
function updateTemplate($template)
{
$array = array(

View File

@@ -22,7 +22,14 @@ class pmbox_manager
$this->pmDB = e107::getDb();
// $this->pmPrefs = $prefs;
$this->pmPrefs = e107::getPlugPref('pm');
$this->pmPrefs = e107::pref('pm');
}
public function prefs()
{
return $this->pmPrefs;
}

View File

@@ -27,16 +27,23 @@ if (!defined('e107_INIT')) { exit; }
global $sc_style; // Needed for the PM_REPLY shortcode!
if(deftrue('BOOTSTRAP') && deftrue('FONTAWESOME'))
{
define('PM_READ_ICON', e107::getParser()->toGlyph('fa-envelope'));
define('PM_UNREAD_ICON', e107::getParser()->toGlyph('fa-envelope-o'));
}
else
{
if (!defined('PM_READ_ICON')) define('PM_READ_ICON', "<img src='".e_PLUGIN_ABS."pm/images/read.png' class='icon S16' alt='".LAN_PM_111."' />");
if (!defined('PM_UNREAD_ICON')) define('PM_UNREAD_ICON', "<img src='".e_PLUGIN_ABS."pm/images/unread.png' class='icon S16' alt='".LAN_PM_27."' />");
}
$sc_style['PM_ATTACHMENT_ICON']['pre'] = " ";
$sc_style['PM_ATTACHMENTS']['pre'] = "<br /><div style='vertical-align:bottom; text-align:left;'>";
$sc_style['PM_ATTACHMENTS']['pre'] = "<div class='alert alert-block alert-info'>";
$sc_style['PM_ATTACHMENTS']['post'] = "</div>";
$sc_style['PM_NEXTPREV']['pre'] = "<tr><td class='forumheader' colspan='6' style='text-align:left'> ".LAN_PM_59;
$sc_style['PM_NEXTPREV']['post'] = "</td></tr>";
//$sc_style['PM_NEXTPREV']['pre'] = "<tr><td class='forumheader' colspan='6' style='text-align:left'> ".LAN_PM_59;
//$sc_style['PM_NEXTPREV']['post'] = "</td></tr>";
$sc_style['PM_EMOTES']['pre'] = "
<tr>
@@ -111,10 +118,10 @@ $PM_INBOX_HEADER = "
";
$PM_INBOX_TABLE = "
<tr>
<tr class='{PM_STATUS_CLASS}'>
<td class='forumheader3'>{PM_SELECT}</td>
<td class='forumheader3'>{PM_READ_ICON}</td>
<td class='forumheader3'>{PM_SUBJECT=link,inbox}{PM_ATTACHMENT_ICON}</td>
<td class='forumheader3'>{PM_ATTACHMENT_ICON}</td>
<td class='forumheader3'>{PM_SUBJECT=link,inbox}</td>
<td class='forumheader3'>{PM_FROM=link}</td>
<td class='forumheader3'>{PM_DATE}</td>
<td class='forumheader3' style='text-align: center; white-space: nowrap'>{PM_DELETE=inbox}&nbsp;{PM_BLOCK_USER}</td>
@@ -129,12 +136,14 @@ $PM_INBOX_EMPTY = "
$PM_INBOX_FOOTER = "
<tr>
<td class='forumheader' colspan='6' style='text-align:center'>
<td class='forumheader' colspan='3'>
<input type='hidden' name='pm_come_from' value='inbox' />
{PM_DELETE_SELECTED}
</td>
</tr>
<td class='forumheader text-right' colspan='3'>
{PM_NEXTPREV=inbox}
</td>
</tr>
</tbody>
</table>
";
@@ -157,8 +166,8 @@ $PM_OUTBOX_HEADER = "
$PM_OUTBOX_TABLE = "
<tr>
<td class='forumheader3'>{PM_SELECT}</td>
<td class='forumheader3'>{PM_READ_ICON}</td>
<td class='forumheader3'>{PM_SUBJECT=link,outbox}{PM_ATTACHMENT_ICON}</td>
<td class='forumheader3'>{PM_ATTACHMENT_ICON}</td>
<td class='forumheader3'>{PM_SUBJECT=link,outbox}</td>
<td class='forumheader3'>{PM_TO=link}</td>
<td class='forumheader3'>{PM_DATE}</td>
<td class='forumheader3' style='text-align: center'>{PM_DELETE=outbox}</td>
@@ -170,7 +179,7 @@ $PM_OUTBOX_EMPTY = "
<td colspan='6' class='forumheader'>".LAN_PM_34."</td>
</tr>
";
/*
$PM_OUTBOX_FOOTER = "
<tr>
<td class='forumheader' colspan='6' style='text-align:center'>
@@ -181,9 +190,24 @@ $PM_OUTBOX_FOOTER = "
{PM_NEXTPREV=outbox}
</tbody>
</table>
";*/
$PM_OUTBOX_FOOTER = "
<tr>
<td class='forumheader' colspan='3'>
<input type='hidden' name='pm_come_from' value='inbox' />
{PM_DELETE_SELECTED}
</td>
<td class='forumheader text-right' colspan='3'>
{PM_NEXTPREV=inbox}
</td>
</tr>
</tbody>
</table>
";
$PM_BLOCKED_HEADER = "
<table class='table table-striped fborder'>
<tr>
@@ -221,29 +245,24 @@ $PM_BLOCKED_FOOTER = "
$PM_SHOW =
"<div style='text-align: center'>
<table class='table fborder'>
"<div class='pm-show' style='text-align: center'>
<table class='table table-bordered table-striped fborder'>
<tr>
<td class='fcaption text-left' colspan='2'>{PM_SUBJECT}</td>
<td class='fcaption text-left' colspan='2'>
<h3>{PM_SUBJECT} <small class='pull-right'>{PM_DATE}</small></h3>
<small>{PM_FROM_TO}</small>
<small class='pull-right' >{PM_READ} {PM_DELETE}</small></td>
</tr>
<tr>
<td class='forumheader3 text-left' style='width:20%; vertical-align:top'>
{PM_FROM_TO}
<br />
<br />
<span class='smalltext'>".LAN_PM_29.":<br />{PM_DATE}</span>
<br />
<br />
<span class='smalltext'>".LAN_PM_30.":<br />{PM_READ}</span>
<br />
<br />
{PM_DELETE}
<td class='forumheader3 text-left' style='vertical-align:top'>
<div class='pm-message'>{PM_MESSAGE}</div>
{PM_ATTACHMENTS}
</td>
<td class='forumheader3 text-left' style='width:80%; vertical-align:top'>{PM_MESSAGE}<br /><br />{PM_ATTACHMENTS}</td>
</tr>
{PM_REPLY}
</table>
</div>
<hr />
";
?>

View File

@@ -90,7 +90,7 @@ require_once(e_PLUGIN.'pm/pm_func.php');
e107::getScParser();
require_once(e_PLUGIN.'pm/pm_shortcodes.php');
require_once(e_PLUGIN.'pm/shortcodes/batch/pm_shortcodes.php');
//setScVar('pm_handler_shortcodes','pmPrefs', $pm_prefs);
$pmManager = new pmbox_manager($pm_prefs);
@@ -157,7 +157,7 @@ if(!isset($pm_menu_template))
if(check_class($pm_prefs['pm_class']))
{
$tp = e107::getParser();
$sc = e107::getScBatch('pm',TRUE);
$sc = e107::getScBatch('pm',TRUE, 'pm');
$pm_inbox = $pmManager->pm_getInfo('inbox');

View File

@@ -78,9 +78,9 @@ PM_BLOCKED_DELETE
DELETE_BLOCKED_SELECTED
*/
if(!class_exists('pm_shortcodes'))
if(!class_exists('plugin_pm_pm_shortcodes'))
{
class pm_shortcodes extends e_shortcode // class pm_handler_shortcodes
class plugin_pm_pm_shortcodes extends e_shortcode // class pm_handler_shortcodes
{
public $pmPrefs; // PM system options
public $pmInfo; // Data relating to current PM being displayed - replaced by $var.
@@ -89,6 +89,7 @@ if(!class_exists('pm_shortcodes'))
public $nextPrev = array(); //XXX In USE ?? // Variables used by nextprev
public $pmManager = NULL; // Pointer to pmbox_manager class instance
public $pmNextPrev = array();
public $pmMode = null;
//public $var = array();
public function __construct()
@@ -98,7 +99,9 @@ if(!class_exists('pm_shortcodes'))
$this->pmPrefs = $pm_prefs;
// print_a($pm_prefs);
require_once(e_PLUGIN."pm/pm_class.php");
$pmClass = new private_message($pm_prefs);
$blocks = $pmClass->block_get_user();
foreach($blocks as $usr)
@@ -226,17 +229,23 @@ if(!class_exists('pm_shortcodes'))
$ret = "
<div id='up_container' >
<span id='upline' style='white-space:nowrap'>
<input class='tbox' type='file' name='file_userfile[]' size='40' />
".e107::getForm()->file('file_userfile[]', array('size'=>40, 'multiple'=>'multiple'))."
</span>
</div>
</div>";
/*
$ret .= "
<input type='button' class='btn btn-default button' value='".LAN_PM_11."' onclick=\"duplicateHTML('upline','up_container');\" />
";
";*/
return $ret;
}
return '';
}
public function sc_pm_attachment_icon()
{
if($this->var['pm_attachments'] != "")
@@ -248,6 +257,8 @@ if(!class_exists('pm_shortcodes'))
public function sc_pm_attachments()
{
$tp = e107::getParser();
if($this->var['pm_attachments'] != '')
{
$attachments = explode(chr(0), $this->var['pm_attachments']);
@@ -257,7 +268,7 @@ if(!class_exists('pm_shortcodes'))
{
list($timestamp, $fromid, $rand, $filename) = explode("_", $a, 4);
$url = $this->url('action/get', array('id' => $this->var['pm_id'], 'index' => $i));
$ret .= "<a href='".$url."'>{$filename}</a><br />";
$ret .= $tp->toGlyph('fa-paperclip')."<a href='".$url."'>{$filename}</a><br />";
$i++;
}
$ret = substr($ret, 0, -3);
@@ -335,6 +346,11 @@ if(!class_exists('pm_shortcodes'))
public function sc_pm_read($parm = '')
{
if($this->pmMode == 'inbox')
{
return;
}
if($this->var['pm_read'] == 0)
{
return LAN_PM_27;
@@ -343,14 +359,14 @@ if(!class_exists('pm_shortcodes'))
{
return LAN_PM_28;
}
require_once(e_HANDLER.'date_handler.php');
if('lapse' != $parm)
{
return convert::convert_date($this->var['pm_read'], $parm);
return e107::getDate()->convert_date($this->var['pm_read'], $parm);
}
else
{
return convert::computeLapse($this->var['pm_read']);
return e107::getDate()->computeLapse($this->var['pm_read']);
}
}
@@ -358,19 +374,19 @@ if(!class_exists('pm_shortcodes'))
public function sc_pm_from_to()
{
$tp = e107::getParser();
$sc = e107::getScBatch('pm',TRUE);
// $sc = e107::getScBatch('pm',TRUE);
if($this->var['pm_from'] == USERID)
if($this->pmMode == 'outbox')
{
$ret = LAN_PM_2.': <br />';
$ret = LAN_PM_2.': ';
$this->var['user_name'] = $this->var['sent_name'];
$ret .= $tp->parseTemplate("{PM_TO=link}", false, $sc);
$ret .= $this->sc_pm_to('link'); // $tp->parseTemplate("{PM_TO=link}", false, $sc);
}
else
{
$ret = LAN_PM_31.': <br />';
$ret = LAN_PM_31.': ';
$this->var['user_name'] = $this->var['from_name'];
$ret .= $tp->parseTemplate("{PM_FROM=link}", false, $sc);
$ret .= $this->sc_pm_from('link');// $tp->parseTemplate("{PM_FROM=link}", false, $sc);
}
return $ret;
}
@@ -380,7 +396,9 @@ if(!class_exists('pm_shortcodes'))
{
$tp = e107::getParser();
$ret = $tp->toHTML($this->var['pm_subject'], true, 'USER_TITLE');
$prm = explode(',',$parm);
if('link' == $prm[0])
{
$extra = '';
@@ -395,7 +413,9 @@ if(!class_exists('pm_shortcodes'))
$ret = "<a href='".$ret."'>".$ret."</a>";
*/
$ret = "<a href='".e_PLUGIN_ABS."pm/pm.php?show.{$this->var['pm_id']}{$extra}'>".$ret."</a>";
$url = e107::url('pm','index')."?show.{$this->var['pm_id']}{$extra}";
$ret = "<a href='".$url."'>".$ret."</a>";
}
return $ret;
}
@@ -434,6 +454,20 @@ if(!class_exists('pm_shortcodes'))
}
}
public function sc_pm_status_class()
{
if($this->var['pm_read'] > 0 )
{
return 'pm-read';
}
else
{
return 'pm-unread';
}
}
public function sc_pm_avatar()
{
@@ -463,23 +497,32 @@ if(!class_exists('pm_shortcodes'))
public function sc_pm_delete($parm = '')
{
if($this->pmMode !== 'inbox' && $this->pmMode !== 'outbox' && empty($parm))
{
return '';
}
if($parm != '')
{
$extra = '.'.$parm;
}
else
{
$extra = '.'.($this->var['pm_from'] == USERID ? 'outbox' : 'inbox');
$extra = '.'.($this->pmMode == 'outbox' ? 'outbox' : 'inbox');
}
if($extra !== 'inbox' && $extra !== 'outbox') return '';
$action = $extra == 'outbox' ? 'delete-out' : 'delete-in';
return "<a href='".$this->url('action/'.$action, 'id='.$this->var['pm_id'])."'><img src='".e_PLUGIN_ABS."pm/images/mail_delete.png' title='".LAN_DELETE."' alt='".LAN_DELETE."' class='icon S16' /></a>";
return "<a class='btn btn-default' title='".LAN_DELETE."' href='".$this->url('action/'.$action, 'id='.$this->var['pm_id'])."'>".PM_DELETE_ICON."</a>";
}
public function sc_pm_delete_selected()
{
return "<input type='submit' name='pm_delete_selected' class='button btn btn-danger' value='".LAN_PM_53."' />";
$tp = e107::getParser();
return e107::getForm()->button('pm_delete_selected',1,'delete',$tp->toGlyph('fa-trash').LAN_PM_53);
// return "<input type='submit' name='pm_delete_selected' class='button btn btn-sm btn-danger' value='".LAN_PM_53."' />";
}
@@ -609,15 +652,92 @@ if(!class_exists('pm_shortcodes'))
return "<input type='submit' name='pm_delete_blocked_selected' class='btn btn-default button' value='".LAN_PM_53."' />";
}
/**
* Convinient url assembling shortcut
*/
public function url($action, $params = array(), $options = array())
{
if(strpos($action, '/') === false) $action = 'view/'.$action;
return e107::getUrl()->create('pm/'.$action, $params, $options);
private function url($route, $params = array(), $options)
{
if(is_string($params))
{
parse_str($params,$params);
}
if(!isset($params['id']) && isset($params['pm_id'])) $params['id'] = $params['pm_id'];
if(is_string($route))
{
$route = explode('/', $route, 2);
}
$base = e107::url('pm','index').'?';
switch($route[1])
{
case 'index':
case 'inbox':
return $base.'inbox';
break;
case 'outbox':
return $base.'outbox';
break;
// we could just remove them all and let only 'message' live
case 'show':
return $base.'show.'.$params['id'];
break;
case 'message':
return $base.'show.'.$params['id'].'.inbox';
break;
case 'sent':
return $base.'show.'.$params['id'].'.outbox';
break;
case 'reply':
return $base.'reply.'.$params['id'];
break;
case 'new':
return $base.'send';
break;
}
switch($route[1])
{
case 'delete-in':
return $base.'del.'.$params['id'].'.inbox';
break;
case 'delete-out':
return $base.'del.'.$params['id'].'.outbox';
break;
case 'delete-blocked':
return $base.'delblocked.'.$params['id'];
break;
case 'block':
return $base.'block.'.$params['id'];
break;
case 'unblock':
return $base.'unblock.'.$params['id'];
break;
case 'get':
return $base.'get.'.$params['id'].'.'.$params['index'];
break;
}
}
}
}

View File

@@ -1,40 +0,0 @@
/* TextboxList sample CSS */
ul.holder { margin: 0; border: 1px solid #999; overflow: hidden; height: auto !important; height: 1%; padding: 4px 5px 0; }
*:first-child+html ul.holder { padding-bottom: 2px; } * html ul.holder { padding-bottom: 2px; } /* ie7 and below */
ul.holder li { float: left; list-style-type: none; margin: 0 5px 4px 0; }
ul.holder li.bit-box, ul.holder li.bit-input input { font: 11px "Lucida Grande", "Verdana"; }
ul.holder li.bit-box { -moz-border-radius: 6px; -webkit-border-radius: 6px; border-radius: 6px; border: 1px solid #CAD8F3; background: #DEE7F8; padding: 1px 5px 2px; }
ul.holder li.bit-box-focus { border-color: #598BEC; background: #598BEC; color: #fff; }
ul.holder li.bit-input input { width: 150px; margin: 0; border: none; outline: 0; padding: 3px 0 2px; } /* no left/right padding here please */
ul.holder li.bit-input input.smallinput { width: 20px; }
/* Facebook demo CSS */
form, #add { border: 1px solid #999; width: 550px; margin: 50px; padding: 20px 30px 10px; }
form ol { font: 11px "Lucida Grande", "Verdana"; margin: 0; padding: 0; }
form ol li.input-text { margin-bottom: 10px; list-style-type: none; border-bottom: 1px dotted #999; padding-bottom: 10px; }
form ol li.input-text label { font-weight: bold; cursor: pointer; display: block; font-size: 13px; margin-bottom: 10px; }
form ol li.input-text input { width: 500px; padding: 5px 5px 6px; font: 11px "Lucida Grande", "Verdana"; border: 1px solid #999; }
form ul.holder { width: 500px; }
#facebook-list ul.holder li.bit-box, #apple-list ul.holder li.bit-box { padding-right: 15px; position: relative; }
#apple-list ul.holder li.bit-input { margin: 0; }
#apple-list ul.holder li.bit-input input.smallinput { width: 5px; }
ul.holder li.bit-hover { background: #BBCEF1; border: 1px solid #6D95E0; }
ul.holder li.bit-box-focus { border-color: #598BEC; background: #598BEC; color: #fff; }
ul.holder li.bit-box a.closebutton { position: absolute; right: 4px; top: 5px; display: block; width: 7px; height: 7px; font-size: 1px; background: url('images/close.gif'); }
ul.holder li.bit-box a.closebutton:hover { background-position: 7px; }
ul.holder li.bit-box-focus a.closebutton, ul.holder li.bit-box-focus a.closebutton:hover { background-position: bottom; }
/* Autocompleter */
#facebook-auto { display: none; position: absolute; width: 512px; background: #eee; }
#facebook-auto .default { padding: 5px 7px; border: 1px solid #ccc; border-width: 0 1px 1px; }
#facebook-auto ul { display: none; margin: 0; padding: 0; overflow: auto; }
#facebook-auto ul li { padding: 5px 12px; z-index: 1000; cursor: pointer; margin: 0; list-style-type: none; border: 1px solid #ccc; border-width: 0 1px 1px; font: 11px "Lucida Grande", "Verdana"; }
#facebook-auto ul li em { font-weight: bold; font-style: normal; background: #ccc; }
#facebook-auto ul li.auto-focus { background: #4173CC; color: #fff; }
#facebook-auto ul li.auto-focus em { background: none; }
#demo ul.holder li.bit-input input { padding: 2px 0 1px; border: 1px solid #999; }
#add a { color: #666; }
#add-test { width: 100px; padding: 2px; }
#button_container { margin-left: 70px; margin-bottom: 30px;}

View File

@@ -1,209 +0,0 @@
/*
Proto!MultiSelect 0.2
- Prototype version required: 6.0
Credits:
- Idea: Facebook
- Guillermo Rauch: Original MooTools script
- Ran Grushkowsky/InteRiders Inc. : Porting into Prototype and further development
Changelog:
- 0.1: translation of MooTools script
- 0.2: renamed from Proto!TextboxList to Proto!MultiSelect, added new features/bug fixes
added feature: support to fetch list on-the-fly using AJAX Credit: Cheeseroll
added feature: support for value/caption
added feature: maximum results to display, when greater displays a scrollbar Credit: Marcel
added feature: filter by the beginning of word only or everywhere in the word Credit: Kiliman
added feature: shows hand cursor when going over options
bug fix: the click event stopped working
bug fix: the cursor does not 'travel' when going up/down the list Credit: Marcel
*/
/* Copyright: InteRiders <http://interiders.com/> - Distributed under MIT - Keep this message! */
var FacebookList = Class.create(TextboxList, {
loptions: $H({
autocomplete: {
'opacity': 0.8,
'maxresults': 10,
'minchars': 1
}
}),
initialize: function($super,element, autoholder, options, func) {
$super(element, options);
this.data = [];
this.autoholder = $(autoholder).setOpacity(this.loptions.get('autocomplete').opacity);
this.autoholder.observe('mouseover',function() {this.curOn = true;}.bind(this)).observe('mouseout',function() {this.curOn = false;}.bind(this));
this.autoresults = this.autoholder.select('ul').first();
var children = this.autoresults.select('li');
children.each(function(el) { this.add({value:el.readAttribute('value'),caption:el.innerHTML}); }, this);
},
autoShow: function(search) {
this.autoholder.setStyle({'display': 'block'});
this.autoholder.descendants().each(function(e) { e.hide() });
if(! search || ! search.strip() || (! search.length || search.length < this.loptions.get('autocomplete').minchars))
{
this.autoholder.select('.default').first().setStyle({'display': 'block'});
this.resultsshown = false;
} else {
this.resultsshown = true;
this.autoresults.setStyle({'display': 'block'}).update('');
if (this.options.get('wordMatch'))
var regexp = new RegExp("(^|\\s)"+search,'i')
else
var regexp = new RegExp(search,'i')
var count = 0;
this.data.filter(function(str) { return str ? regexp.test(str.evalJSON(true).caption) : false; }).each(function(result, ti) {
count++;
if(ti >= this.loptions.get('autocomplete').maxresults) return;
var that = this;
var el = new Element('li');
el.observe('click',function(e) {
e.stop();
that.autoAdd(this);
}).observe('mouseover',function() {
that.autoFocus(this);
}).update(this.autoHighlight(result.evalJSON(true).caption, search));
this.autoresults.insert(el);
el.cacheData('result', result.evalJSON(true));
if(ti == 0) this.autoFocus(el);
}, this);
}
if (count > this.options.get('results'))
this.autoresults.setStyle({'height': (this.options.get('results')*24)+'px'});
else
this.autoresults.setStyle({'height': (count?(count*24):0)+'px'});
return this;
},
autoHighlight: function(html, highlight) {
return html.gsub(new RegExp(highlight,'i'), function(match) {
return '<em>' + match[0] + '</em>';
});
},
autoHide: function() {
this.resultsshown = false;
this.autoholder.hide();
return this;
},
autoFocus: function(el) {
if(! el) return;
if(this.autocurrent) this.autocurrent.removeClassName('auto-focus');
this.autocurrent = el.addClassName('auto-focus');
return this;
},
autoMove: function(direction) {
if(!this.resultsshown) return;
this.autoFocus(this.autocurrent[(direction == 'up' ? 'previous' : 'next')]());
this.autoresults.scrollTop = this.autocurrent.positionedOffset()[1]-this.autocurrent.getHeight();
return this;
},
autoFeed: function(text) {
if (this.data.indexOf(Object.toJSON(text)) == -1)
this.data.push(Object.toJSON(text));
return this;
},
autoAdd: function(el) {
if(!el || ! el.retrieveData('result')) return;
this.add(el.retrieveData('result'));
delete this.data[this.data.indexOf(Object.toJSON(el.retrieveData('result')))];
this.autoHide();
var input = this.lastinput || this.current.retrieveData('input');
input.clear().focus();
return this;
},
createInput: function($super,options) {
var li = $super(options);
var input = li.retrieveData('input');
input.observe('keydown', function(e) {
this.dosearch = false;
switch(e.keyCode) {
case Event.KEY_UP: e.stop(); return this.autoMove('up');
case Event.KEY_DOWN: e.stop(); return this.autoMove('down');
case Event.KEY_RETURN:
e.stop();
if(! this.autocurrent) break;
this.autoAdd(this.autocurrent);
this.autocurrent = false;
this.autoenter = true;
break;
case Event.KEY_ESC:
this.autoHide();
if(this.current && this.current.retrieveData('input'))
this.current.retrieveData('input').clear();
break;
default: this.dosearch = true;
}
}.bind(this));
input.observe('keyup',function(e) {
switch(e.keyCode) {
case Event.KEY_UP:
case Event.KEY_DOWN:
case Event.KEY_RETURN:
case Event.KEY_ESC:
break;
default:
if (!Object.isUndefined(this.options.get('fetchFile'))) {
new Ajax.Request(this.options.get('fetchFile'), {
parameters: {keyword: input.value},
onSuccess: function(transport) {
transport.responseText.evalJSON(true).each(function(t){this.autoFeed(t)}.bind(this));
this.autoShow(input.value);
}.bind(this)
});
}
else
if(this.dosearch) this.autoShow(input.value);
}
}.bind(this));
input.observe(Prototype.Browser.IE ? 'keydown' : 'keypress', function(e) {
if(this.autoenter) e.stop();
this.autoenter = false;
}.bind(this));
return li;
},
createBox: function($super,text, options) {
var li = $super(text, options);
li.observe('mouseover',function() {
this.addClassName('bit-hover');
}).observe('mouseout',function() {
this.removeClassName('bit-hover')
});
var a = new Element('a', {
'href': '#',
'class': 'closebutton'
}
);
a.observe('click',function(e) {
e.stop();
if(! this.current) this.focus(this.maininput);
this.dispose(li);
}.bind(this));
li.insert(a).cacheData('text', Object.toJSON(text));
return li;
}
});
Element.addMethods({
onBoxDispose: function(item,obj) { obj.autoFeed(item.retrieveData('text').evalJSON(true)); },
onInputFocus: function(el,obj) { obj.autoShow(); },
onInputBlur: function(el,obj) {
obj.lastinput = el;
if(!obj.curOn) {
obj.blurhide = obj.autoHide.bind(obj).delay(0.1);
}
},
filter:function(D,E){var C=[];for(var B=0,A=this.length;B<A;B++){if(D.call(E,this[B],B,this)){C.push(this[B]);}}return C;}
});

View File

@@ -1,244 +0,0 @@
/*
Proto!MultiSelect 0.2
- Prototype version required: 6.0
Credits:
- Idea: Facebook + Apple Mail
- Caret position method: Diego Perini <http://javascript.nwbox.com/cursor_position/cursor.js>
- Guillermo Rauch: Original MooTools script
- Ran Grushkowsky/InteRiders Inc. : Porting into Prototype and further development
Changelog:
- 0.1: translation of MooTools script
- 0.2: renamed from Proto!TextboxList to Proto!MultiSelect, added new features/bug fixes
added feature: support to fetch list on-the-fly using AJAX Credit: Cheeseroll
added feature: support for value/caption
added feature: maximum results to display, when greater displays a scrollbar Credit: Marcel
added feature: filter by the beginning of word only or everywhere in the word Credit: Kiliman
added feature: shows hand cursor when going over options
bug fix: the click event stopped working
bug fix: the cursor does not 'travel' when going up/down the list Credit: Marcel
*/
/* Copyright: InteRiders <http://interiders.com/> - Distributed under MIT - Keep this message! */
var ResizableTextbox = Class.create({
options: $H({
min: 5,
max: 500,
step: 7
}),
initialize: function(element, options) {
var that = this;
this.options.update(options);
this.el = $(element);
this.width = this.el.offsetWidth;
this.el.observe(
'keyup', function() {
var newsize = that.options.get('step') * $F(this).length;
if(newsize <= that.options.get('min')) newsize = that.width;
if(! ($F(this).length == this.retrieveData('rt-value') || newsize <= that.options.min || newsize >= that.options.max))
this.setStyle({'width': newsize});
}).observe('keydown', function() {
this.cacheData('rt-value', $F(this).length);
});
}
});
var TextboxList = Class.create({
options: $H({/*
onFocus: $empty,
onBlur: $empty,
onInputFocus: $empty,
onInputBlur: $empty,
onBoxFocus: $empty,
onBoxBlur: $empty,
onBoxDispose: $empty,*/
resizable: {},
className: 'bit',
separator: '###',
extrainputs: true,
startinput: true,
hideempty: true,
fetchFile: undefined,
results: 10,
wordMatch: false
}),
initialize: function(element, options) {
this.options.update(options);
this.element = $(element).hide();
this.bits = new Hash();
this.events = new Hash();
this.count = 0;
this.current = false;
this.maininput = this.createInput({'class': 'maininput'});
this.holder = new Element('ul', {
'class': 'holder'
}).insert(this.maininput);
this.element.insert({'before':this.holder});
this.holder.observe('click', function(event){
event.stop();
if(this.maininput != this.current) this.focus(this.maininput);
}.bind(this));
this.makeResizable(this.maininput);
this.setEvents();
},
setEvents: function() {
document.observe(Prototype.Browser.IE ? 'keydown' : 'keypress', function(e) {
if(! this.current) return;
if(this.current.retrieveData('type') == 'box' && e.keyCode == Event.KEY_BACKSPACE) e.stop();
}.bind(this));
document.observe(
'keyup', function(e) {
e.stop();
if(! this.current) return;
switch(e.keyCode){
case Event.KEY_LEFT: return this.move('left');
case Event.KEY_RIGHT: return this.move('right');
case Event.KEY_DELETE:
case Event.KEY_BACKSPACE: return this.moveDispose();
}
}.bind(this)).observe(
'click', function() { document.fire('blur'); }.bindAsEventListener(this)
);
},
update: function() {
this.element.value = this.bits.values().join(this.options.get('separator'));
return this;
},
add: function(text, html) {
var id = this.options.get('className') + '-' + this.count++;
var el = this.createBox($pick(html, text), {'id': id});
(this.current || this.maininput).insert({'before':el});
el.observe('click', function(e) {
e.stop();
this.focus(el);
}.bind(this));
this.bits.set(id, text.value);
if(this.options.get('extrainputs') && (this.options.get('startinput') || el.previous())) this.addSmallInput(el,'before');
return el;
},
addSmallInput: function(el, where) {
var input = this.createInput({'class': 'smallinput'});
el.insert({}[where] = input);
input.cacheData('small', true);
this.makeResizable(input);
if(this.options.get('hideempty')) input.hide();
return input;
},
dispose: function(el) {
this.bits.unset(el.id);
if(el.previous() && el.previous().retrieveData('small')) el.previous().remove();
if(this.current == el) this.focus(el.next());
if(el.retrieveData('type') == 'box') el.onBoxDispose(this);
el.remove();
return this;
},
focus: function(el, nofocus) {
if(! this.current) el.fire('focus');
else if(this.current == el) return this;
this.blur();
el.addClassName(this.options.get('className') + '-' + el.retrieveData('type') + '-focus');
if(el.retrieveData('small')) el.setStyle({'display': 'block'});
if(el.retrieveData('type') == 'input') {
el.onInputFocus(this);
if(! nofocus) this.callEvent(el.retrieveData('input'), 'focus');
}
else el.fire('onBoxFocus');
this.current = el;
return this;
},
blur: function(noblur) {
if(! this.current) return this;
if(this.current.retrieveData('type') == 'input') {
var input = this.current.retrieveData('input');
if(! noblur) this.callEvent(input, 'blur');
input.onInputBlur(this);
}
else this.current.fire('onBoxBlur');
if(this.current.retrieveData('small') && ! input.get('value') && this.options.get('hideempty'))
this.current.hide();
this.current.removeClassName(this.options.get('className') + '-' + this.current.retrieveData('type') + '-focus');
this.current = false;
return this;
},
createBox: function(text, options) {
return new Element('li', options).addClassName(this.options.get('className') + '-box').update(text.caption).cacheData('type', 'box');
},
createInput: function(options) {
var li = new Element('li', {'class': this.options.get('className') + '-input'});
var el = new Element('input', Object.extend(options,{'type': 'text'}));
el.observe('click', function(e) { e.stop(); }).observe('focus', function(e) { if(! this.isSelfEvent('focus')) this.focus(li, true); }.bind(this)).observe('blur', function() { if(! this.isSelfEvent('blur')) this.blur(true); }.bind(this)).observe('keydown', function(e) { this.cacheData('lastvalue', this.value).cacheData('lastcaret', this.getCaretPosition()); });
var tmp = li.cacheData('type', 'input').cacheData('input', el).insert(el);
return tmp;
},
callEvent: function(el, type) {
this.events.set(type, el);
el[type]();
},
isSelfEvent: function(type) {
return (this.events.get(type)) ? !! this.events.unset(type) : false;
},
makeResizable: function(li) {
var el = li.retrieveData('input');
el.cacheData('resizable', new ResizableTextbox(el, Object.extend(this.options.get('resizable'),{min: el.offsetWidth, max: (this.element.getWidth()?this.element.getWidth():0)})));
return this;
},
checkInput: function() {
var input = this.current.retrieveData('input');
return (! input.retrieveData('lastvalue') || (input.getCaretPosition() === 0 && input.retrieveData('lastcaret') === 0));
},
move: function(direction) {
var el = this.current[(direction == 'left' ? 'previous' : 'next')]();
if(el && (! this.current.retrieveData('input') || ((this.checkInput() || direction == 'right')))) this.focus(el);
return this;
},
moveDispose: function() {
if(this.current.retrieveData('type') == 'box') return this.dispose(this.current);
if(this.checkInput() && this.bits.keys().length && this.current.previous()) return this.focus(this.current.previous());
}
});
//helper functions
Element.addMethods({
getCaretPosition: function() {
if (this.createTextRange) {
var r = document.selection.createRange().duplicate();
r.moveEnd('character', this.value.length);
if (r.text === '') return this.value.length;
return this.value.lastIndexOf(r.text);
} else return this.selectionStart;
},
cacheData: function(element, key, value) {
if (Object.isUndefined(this[$(element).identify()]) || !Object.isHash(this[$(element).identify()]))
this[$(element).identify()] = $H();
this[$(element).identify()].set(key,value);
return element;
},
retrieveData: function(element,key) {
return this[$(element).identify()].get(key);
}
});
function $pick(){for(var B=0,A=arguments.length;B<A;B++){if(!Object.isUndefined(arguments[B])){return arguments[B];}}return null;}

View File

@@ -1,161 +0,0 @@
<?php
/*
* Copyright (C) 2008-2011 e107 Inc (e107.org), Licensed under GNU GPL (http://www.gnu.org/licenses/gpl.txt)
* $Id$
*
* PM Default URL configuration
* TODO - SEF URL configuration
*/
if (!defined('e107_INIT')){ exit; }
class plugin_pm_url extends eUrlConfig
{
public function config()
{
return array(
'config' => array(
'noSingleEntry' => true, // [optional] default false; disallow this module to be shown via single entry point when this config is used
'legacy' => '{e_PLUGIN}pm/pm.php', // this config won't work in single entry point mod (legacy not used at all), so just set this to default plugin file to notify router it's legacy module
'format' => 'get', // get|path - notify core for the current URL format, if set to 'get' rules will be ignored
'selfCreate' => true, // [optional] default false; use only this->create() method, no core routine URL creating
'defaultRoute' => 'view/inbox', // [optional] default empty; route (no leading module) used when module is found with no additional controller/action information e.g. /news/
),
// rule set array
'rules' => array()
);
}
/**
* Describe all pm routes.
* Routes vs legacy queries:
* view/inbox -> ?inbox (default route, resolved on index/index)
* view/outbox -> ?outbox
* view/message?id=xxx -> ?show.xxx.inbox
* view/sent?id=xxx -> ?show.xxx.outbox
* view/show?id=xxx -> ?show.xxx (investigate why we have dupps, good time to remove them!)
* view/reply?id=xxx -> ?reply.xxx
* view/send -> ?send
* action/delete-in?id=xx -> ?del.xxx.inbox
* action/delete-out?id=xx -> ?del.xxx.outbox
* action/delete-blocked?id=xxx -> ?delblocked.xxx
* action/block?id=xx -> ?block.xxx
* action/unblock?id=xx -> ?unblock.xxx
* action/get?id=xxx&index=yyy -> ?get.xxx.yyy
*/
public function create($route, $params = array(), $options = array())
{
if(is_string($route)) $route = explode('/', $route, 2);
if(!varset($route[0]) || 'index' == $route[0]) $route[0] = 'view';
if(!varset($route[1])) $route[1] = 'inbox';
$base = e107::getInstance()->getFolder('plugins').'pm/';
//var_dump($options, $route, $params);
if($route[0] == 'view')
{
if(!isset($params['id']) && isset($params['pm_id'])) $params['id'] = $params['pm_id'];
switch($route[1])
{
case 'index':
case 'inbox':
$this->legacyQueryString = 'inbox';
return $base.'pm.php?inbox';
break;
case 'outbox':
$this->legacyQueryString = 'outbox';
return $base.'pm.php?outbox';
break;
// we could just remove them all and let only 'message' live
case 'show':
$this->legacyQueryString = 'show.'.$params['id'];
return $base.'pm.php?show.'.$params['id'];
break;
case 'message':
$this->legacyQueryString = 'show.'.$params['id'].'.inbox';
return $base.'pm.php?show.'.$params['id'].'.inbox';
break;
case 'sent':
$this->legacyQueryString = 'show.'.$params['id'].'.outbox';
return $base.'pm.php?show.'.$params['id'].'.outbox';
break;
case 'reply':
$this->legacyQueryString = 'reply.'.$params['id'];
return $base.'pm.php?reply.'.$params['id'];
break;
case 'new':
$this->legacyQueryString = 'send';
return $base.'pm.php?send';
break;
}
}
elseif($route[0] == 'action')
{
if(!isset($params['id']) && isset($params['pm_id'])) $params['id'] = $params['pm_id'];
switch($route[1])
{
case 'delete-in':
$this->legacyQueryString = 'del.'.$params['id'].'.inbox';
return $base.'pm.php?del.'.$params['id'].'.inbox';
break;
case 'delete-out':
$this->legacyQueryString = 'del.'.$params['id'].'.outbox';
return $base.'pm.php?del.'.$params['id'].'.outbox';
break;
case 'delete-blocked':
$this->legacyQueryString = 'delblocked.'.$params['id'];
return $base.'pm.php?delblocked.'.$params['id'];
break;
case 'block':
$this->legacyQueryString = 'block.'.$params['id'];
return $base.'pm.php?block.'.$params['id'];
break;
case 'unblock':
$this->legacyQueryString = 'unblock.'.$params['id'];
return $base.'pm.php?unblock.'.$params['id'];
break;
case 'get':
$this->legacyQueryString = 'get.'.$params['id'].'.'.$params['index'];
return $base.'pm.php?get.'.$params['id'].'.'.$params['index'];
break;
}
}
return false;
}
/**
* Admin callback
* Language file not loaded as all language data is inside the lan_eurl.php (loaded by default on administration URL page)
*/
public function admin()
{
// static may be used for performance
e107::plugLan('pm', 'admin_pm', true);
static $admin = array(
'labels' => array(
'name' => LAN_PLUGIN_PM_NAME, // Module name
'label' => LAN_PLUGIN_PM_URL_DEFAULT_LABEL, // Current profile name
'description' => LAN_PLUGIN_PM_URL_DEFAULT_DESCR, //
'examples' => array("{e_PLUGIN_ABS}pm/pm.php")
),
'form' => array(), // Under construction - additional configuration options
'callbacks' => array(), // Under construction - could be used for e.g. URL generator functionallity
);
return $admin;
}
}

View File

@@ -183,6 +183,7 @@ class theme_shortcodes extends e_shortcode
$text = '
<ul class="nav navbar-nav navbar-right'.$direction.'">
<li class="dropdown">{PM_NAV}</li>
<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">{SETIMAGE: w=20} {USER_AVATAR: shape=circle} '. USERNAME.' <b class="caret"></b></a>
<ul class="dropdown-menu">
<li>