inital commit

This commit is contained in:
2026-06-19 20:08:01 +06:00
commit 8a5abeeae4
13128 changed files with 3192007 additions and 0 deletions

67
webroot/forum/.htaccess Normal file
View File

@@ -0,0 +1,67 @@
Options -MultiViews +FollowSymlinks -Indexes
#
# If mod_security is enabled, attempt to disable it.
# - Note, this will work on the majority of hosts but on
# MediaTemple, it is known to cause random Internal Server
# errors. For MediaTemple, please remove the block below
#
<IfModule mod_security.c>
# Turn off mod_security filtering.
SecFilterEngine Off
# The below probably isn't needed, but better safe than sorry.
SecFilterScanPOST Off
</IfModule>
#
# MyBB "search engine friendly" URL rewrites
# - Note, for these to work with MyBB please make sure you have
# the setting enabled in the Admin CP and you have this file
# named .htaccess
#
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^forum-([0-9]+)\.html$ forumdisplay.php?fid=$1 [L,QSA]
RewriteRule ^forum-([0-9]+)-page-([0-9]+)\.html$ forumdisplay.php?fid=$1&page=$2 [L,QSA]
RewriteRule ^thread-([0-9]+)\.html$ showthread.php?tid=$1 [L,QSA]
RewriteRule ^thread-([0-9]+)-page-([0-9]+)\.html$ showthread.php?tid=$1&page=$2 [L,QSA]
RewriteRule ^thread-([0-9]+)-lastpost\.html$ showthread.php?tid=$1&action=lastpost [L,QSA]
RewriteRule ^thread-([0-9]+)-nextnewest\.html$ showthread.php?tid=$1&action=nextnewest [L,QSA]
RewriteRule ^thread-([0-9]+)-nextoldest\.html$ showthread.php?tid=$1&action=nextoldest [L,QSA]
RewriteRule ^thread-([0-9]+)-newpost\.html$ showthread.php?tid=$1&action=newpost [L,QSA]
RewriteRule ^thread-([0-9]+)-post-([0-9]+)\.html$ showthread.php?tid=$1&pid=$2 [L,QSA]
RewriteRule ^post-([0-9]+)\.html$ showthread.php?pid=$1 [L,QSA]
RewriteRule ^announcement-([0-9]+)\.html$ announcements.php?aid=$1 [L,QSA]
RewriteRule ^user-([0-9]+)\.html$ member.php?action=profile&uid=$1 [L,QSA]
RewriteRule ^calendar-([0-9]+)\.html$ calendar.php?calendar=$1 [L,QSA]
RewriteRule ^calendar-([0-9]+)-year-([0-9]+)-month-([0-9]+)\.html$ calendar.php?calendar=$1&year=$2&month=$3 [L,QSA]
RewriteRule ^calendar-([0-9]+)-year-([0-9]+)-month-([0-9]+)-day-([0-9]+)\.html$ calendar.php?action=dayview&calendar=$1&year=$2&month=$3&day=$4 [L,QSA]
RewriteRule ^calendar-([0-9]+)-week-(n?[0-9]+)\.html$ calendar.php?action=weekview&calendar=$1&week=$2 [L,QSA]
RewriteRule ^event-([0-9]+)\.html$ calendar.php?action=event&eid=$1 [L,QSA]
<IfModule mod_env.c>
SetEnv SEO_SUPPORT 1
</IfModule>
</IfModule>
#
# If Apache is compiled with built in mod_deflade/GZIP support
# then GZIP Javascript, CSS, HTML and XML so they're sent to
# the client faster.
#
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/css text/html application/xhtml+xml text/xml application/xml text/plain text/x-component application/javascript application/x-javascript application/rss+xml application/atom+xml application/json application/manifest+json application/x-web-app-manifest+json application/vnd.ms-fontobject application/font-sfnt application/font-woff application/font-woff2 image/svg+xml image/x-icon
</IfModule>
# Note: You are able to choose a different name in the Admin CP. If you've done that you need to change it here too
<Files "error.log">
Order Deny,Allow
Deny from all
</Files>

View File

@@ -0,0 +1,7 @@
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
<IfModule mod_authz_core.c>
Require all denied
</IfModule>

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,291 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
/**
* Generate a data grid/table.
*/
class DefaultTable
{
/**
* @var array Array of cells for the current row.
*/
private $_cells = array();
/**
* @var array Array of rows for the current table.
*/
private $_rows = array();
/**
* @var array Array of headers for the current table.
*/
private $_headers = array();
/**
* Construct an individual cell for this table.
*
* @param string $data The HTML content for this cell.
* @param array $extra Array of extra information about this cell (class, id, colspan, rowspan, width)
*/
function construct_cell($data, $extra=array())
{
$this->_cells[] = array("data" => $data, "extra" => $extra);
}
/**
* Construct a row from the earlier defined constructed cells for the table.
*
* @param array $extra Array of extra information about this row (class, id)
*/
function construct_row($extra = array())
{
$i = 1;
$cells = '';
// We construct individual cells here
foreach($this->_cells as $key => $cell)
{
$cells .= "\t\t\t<td";
if(!isset($cell['extra']['class']))
{
$cell['extra']['class'] = '';
}
if($key == 0)
{
$cell['extra']['class'] .= " first";
}
elseif(!isset($this->_cells[$key+1]))
{
$cell['extra']['class'] .= " last";
}
if($i == 2)
{
$cell['extra']['class'] .= " alt_col";
$i = 0;
}
$i++;
if($cell['extra']['class'])
{
$cells .= " class=\"".trim($cell['extra']['class'])."\"";
}
if(isset($cell['extra']['style']))
{
$cells .= " style=\"".$cell['extra']['style']."\"";
}
if(isset($cell['extra']['id']))
{
$cells .= " id=\"".$cell['extra']['id']."\"";
}
if(isset($cell['extra']['colspan']) && $cell['extra']['colspan'] > 1)
{
$cells .= " colspan=\"".$cell['extra']['colspan']."\"";
}
if(isset($cell['extra']['rowspan']) && $cell['extra']['rowspan'] > 1)
{
$cells .= " rowspan=\"".$cell['extra']['rowspan']."\"";
}
if(isset($cell['extra']['width']))
{
$cells .= " width=\"".$cell['extra']['width']."\"";
}
$cells .= ">";
$cells .= $cell['data'];
$cells .= "</td>\n";
}
$data['cells'] = $cells;
$data['extra'] = $extra;
$this->_rows[] = $data;
$this->_cells = array();
}
/**
* return the cells of a row for the table based row.
*
* @param string $row_id The id of the row you want to give it.
* @param boolean $return Whether or not to return or echo the resultant contents.
* @return string The output of the row cells (optional).
*/
function output_row_cells($row_id, $return=false)
{
$row = $this->_rows[$row_id]['cells'];
if(!$return)
{
echo $row;
}
else
{
return $row;
}
}
/**
* Count the number of rows in the table. Useful for displaying a 'no rows' message.
*
* @return int The number of rows in the table.
*/
function num_rows()
{
return count($this->_rows);
}
/**
* Construct a header cell for this table.
*
* @param string $data The HTML content for this header cell.
* @param array $extra Array of extra information for this header cell (class, style, colspan, width)
*/
function construct_header($data, $extra=array())
{
$this->_headers[] = array("data" => $data, "extra" => $extra);
}
/**
* Output this table to the browser.
*
* @param string $heading The heading for this table.
* @param int $border The border width for this table.
* @param string $class The class for this table.
* @param boolean $return Whether or not to return or echo the resultant contents.
* @return string The output of the row cells (optional).
*/
function output($heading="", $border=1, $class="general", $return=false)
{
if($return == true)
{
return $this->construct_html($heading, $border, $class);
}
else
{
echo $this->construct_html($heading, $border, $class);
}
}
/**
* Fetch the built HTML for this table.
*
* @param string $heading The heading for this table.
* @param int $border The border width for this table.
* @param string $class The class for this table.
* @param string $table_id The id for this table.
* @return string The built HTML.
*/
function construct_html($heading="", $border=1, $class=null, $table_id="")
{
$table = '';
if($border == 1)
{
$table .= "<div class=\"border_wrapper\">\n";
if($heading != "")
{
$table .= " <div class=\"title\">".$heading."</div>\n";
}
}
$table .= "<table";
if(!is_null($class))
{
if(!$class)
{
$class = "general";
}
$table .= " class=\"".$class."\"";
}
if($table_id != "")
{
$table .= " id=\"".$table_id."\"";
}
$table .= " cellspacing=\"0\">\n";
if($this->_headers)
{
$table .= "\t<thead>\n";
$table .= "\t\t<tr>\n";
foreach($this->_headers as $key => $data)
{
$table .= "\t\t\t<th";
if($key == 0)
{
$data['extra']['class'] .= " first";
}
elseif(!isset($this->_headers[$key+1]))
{
$data['extra']['class'] .= " last";
}
if(isset($data['extra']['class']))
{
$table .= " class=\"".$data['extra']['class']."\"";
}
if(isset($data['extra']['style']))
{
$table .= " style=\"".$data['extra']['style']."\"";
}
if(isset($data['extra']['width']))
{
$table .= " width=\"".$data['extra']['width']."\"";
}
if(isset($data['extra']['colspan']) && $data['extra']['colspan'] > 1)
{
$table .= " colspan=\"".$data['extra']['colspan']."\"";
}
$table .= ">".$data['data']."</th>\n";
}
$table .= "\t\t</tr>\n";
$table .= "\t</thead>\n";
}
$table .= "\t<tbody>\n";
$i = 1;
foreach($this->_rows as $key => $table_row)
{
$table .= "\t\t<tr";
if(isset($table_row['extra']['id']))
{
$table .= " id=\"{$table_row['extra']['id']}\"";
}
if(!isset($table_row['extra']['class']))
{
$table_row['extra']['class'] = '';
}
if($key == 0)
{
$table_row['extra']['class'] .= " first";
}
else if(!isset($this->_rows[$key+1]))
{
$table_row['extra']['class'] .= " last";
}
if($i == 2 && !isset($table_row['extra']['no_alt_row']))
{
$table_row['extra']['class'] .= " alt_row";
$i = 0;
}
$i++;
if($table_row['extra']['class'])
{
$table .= " class=\"".trim($table_row['extra']['class'])."\"";
}
$table .= ">\n";
$table .= $table_row['cells'];
$table .= "\t\t</tr>\n";
}
$table .= "\t</tbody>\n";
$table .= "</table>\n";
// Clean up
$this->_cells = $this->_rows = $this->_headers = array();
if($border == 1)
{
$table .= "</div>";
}
return $table;
}
}

View File

@@ -0,0 +1,830 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
/**
* Logs an administrator action taking any arguments as log data.
*/
function log_admin_action()
{
global $db, $mybb;
$data = func_get_args();
if(count($data) == 1 && is_array($data[0]))
{
$data = $data[0];
}
if(!is_array($data))
{
$data = array($data);
}
$log_entry = array(
"uid" => (int)$mybb->user['uid'],
"ipaddress" => $db->escape_binary(my_inet_pton(get_ip())),
"dateline" => TIME_NOW,
"module" => $db->escape_string($mybb->get_input('module')),
"action" => $db->escape_string($mybb->get_input('action')),
"data" => $db->escape_string(@my_serialize($data))
);
$db->insert_query("adminlog", $log_entry);
}
/**
* Redirects the current user to a specified URL.
*
* @param string $url The URL to redirect to
*/
function admin_redirect($url)
{
if(!headers_sent())
{
$url = str_replace("&amp;", "&", $url);
header("Location: $url");
}
else
{
echo "<meta http-equiv=\"refresh\" content=\"0; url={$url}\">";
}
exit;
}
/**
* Updates an administration session data array.
*
* @param string $name The name of the item in the data session to update
* @param mixed $value The value
*/
function update_admin_session($name, $value)
{
global $db, $admin_session;
$admin_session['data'][$name] = $value;
$updated_session = array(
"data" => $db->escape_string(@my_serialize($admin_session['data']))
);
$db->update_query("adminsessions", $updated_session, "sid='{$admin_session['sid']}'");
}
/**
* Saves a "flash message" for the current user to be shown on their next page visit.
*
* @param string $message The message to show
* @param string $type The type of message to be shown (success|error)
*/
function flash_message($message, $type='')
{
$flash = array('message' => $message, 'type' => $type);
update_admin_session('flash_message', $flash);
}
/**
* Draw pagination for pages in the Admin CP.
*
* @param int $page The current page we're on
* @param int $per_page The number of items per page
* @param int $total_items The total number of items in this collection
* @param string $url The URL for pagination of this collection
* @return string The built pagination
*/
function draw_admin_pagination($page, $per_page, $total_items, $url)
{
global $mybb, $lang;
if($total_items <= $per_page)
{
return '';
}
$pages = ceil($total_items / $per_page);
$pagination = "<div class=\"pagination\"><span class=\"pages\">{$lang->pages}: </span>\n";
if($page > 1)
{
$prev = $page-1;
$prev_page = fetch_page_url($url, $prev);
$pagination .= "<a href=\"{$prev_page}\" class=\"pagination_previous\">&laquo; {$lang->previous}</a> \n";
}
// Maximum number of "page bits" to show
if(!$mybb->settings['maxmultipagelinks'])
{
$mybb->settings['maxmultipagelinks'] = 5;
}
$max_links = $mybb->settings['maxmultipagelinks'];
$from = $page-floor($mybb->settings['maxmultipagelinks']/2);
$to = $page+floor($mybb->settings['maxmultipagelinks']/2);
if($from <= 0)
{
$from = 1;
$to = $from+$max_links-1;
}
if($to > $pages)
{
$to = $pages;
$from = $pages-$max_links+1;
if($from <= 0)
{
$from = 1;
}
}
if($to == 0)
{
$to = $pages;
}
if($from > 2)
{
$first = fetch_page_url($url, 1);
$pagination .= "<a href=\"{$first}\" title=\"{$lang->page} 1\" class=\"pagination_first\">1</a> ... ";
}
for($i = $from; $i <= $to; ++$i)
{
$page_url = fetch_page_url($url, $i);
if($page == $i)
{
$pagination .= "<span class=\"pagination_current\">{$i}</span> \n";
}
else
{
$pagination .= "<a href=\"{$page_url}\" title=\"{$lang->page} {$i}\">{$i}</a> \n";
}
}
if($to < $pages)
{
$last = fetch_page_url($url, $pages);
$pagination .= "... <a href=\"{$last}\" title=\"{$lang->page} {$pages}\" class=\"pagination_last\">{$pages}</a>";
}
if($page < $pages)
{
$next = $page+1;
$next_page = fetch_page_url($url, $next);
$pagination .= " <a href=\"{$next_page}\" class=\"pagination_next\">{$lang->next} &raquo;</a>\n";
}
$pagination .= "</div>\n";
return $pagination;
}
/**
* Builds a CSV parent list for a particular forum.
*
* @param int $fid The forum ID
* @param string $navsep Optional separator - defaults to comma for CSV list
* @return string The built parent list
*/
function make_parent_list($fid, $navsep=",")
{
global $pforumcache, $db;
if(!$pforumcache)
{
$query = $db->simple_select("forums", "name, fid, pid", "", array("order_by" => "disporder, pid"));
while($forum = $db->fetch_array($query))
{
$pforumcache[$forum['fid']][$forum['pid']] = $forum;
}
}
reset($pforumcache);
reset($pforumcache[$fid]);
foreach($pforumcache[$fid] as $key => $forum)
{
if($fid == $forum['fid'])
{
if($pforumcache[$forum['pid']])
{
$navigation = make_parent_list($forum['pid'], $navsep).$navigation;
}
if($navigation)
{
$navigation .= $navsep;
}
$navigation .= $forum['fid'];
}
}
return $navigation;
}
/**
* @param int $fid
*/
function save_quick_perms($fid)
{
global $db, $inherit, $canview, $canpostthreads, $canpostreplies, $canpostpolls, $canpostattachments, $cache;
$permission_fields = array();
$field_list = $db->show_fields_from("forumpermissions");
foreach($field_list as $field)
{
if(strpos($field['Field'], 'can') !== false || strpos($field['Field'], 'mod') !== false)
{
$permission_fields[$field['Field']] = 1;
}
}
// "Can Only View Own Threads" and "Can Only Reply Own Threads" permissions are forum permission only options
$usergroup_permission_fields = $permission_fields;
unset($usergroup_permission_fields['canonlyviewownthreads']);
unset($usergroup_permission_fields['canonlyreplyownthreads']);
$query = $db->simple_select("usergroups", "gid");
while($usergroup = $db->fetch_array($query))
{
$query2 = $db->simple_select("forumpermissions", $db->escape_string(implode(',', array_keys($permission_fields))), "fid='{$fid}' AND gid='{$usergroup['gid']}'", array('limit' => 1));
$existing_permissions = $db->fetch_array($query2);
if(!$existing_permissions)
{
$query2 = $db->simple_select("usergroups", $db->escape_string(implode(',', array_keys($usergroup_permission_fields))), "gid='{$usergroup['gid']}'", array('limit' => 1));
$existing_permissions = $db->fetch_array($query2);
}
// Delete existing permissions
$db->delete_query("forumpermissions", "fid='{$fid}' AND gid='{$usergroup['gid']}'");
// Only insert the new ones if we're using custom permissions
if($inherit[$usergroup['gid']] != 1)
{
if($canview[$usergroup['gid']] == 1)
{
$pview = 1;
}
else
{
$pview = 0;
}
if($canpostthreads[$usergroup['gid']] == 1)
{
$pthreads = 1;
}
else
{
$pthreads = 0;
}
if($canpostreplies[$usergroup['gid']] == 1)
{
$preplies = 1;
}
else
{
$preplies = 0;
}
if($canpostpolls[$usergroup['gid']] == 1)
{
$ppolls = 1;
}
else
{
$ppolls = 0;
}
if(!$preplies && !$pthreads)
{
$ppost = 0;
}
else
{
$ppost = 1;
}
$insertquery = array(
"fid" => (int)$fid,
"gid" => (int)$usergroup['gid'],
"canview" => (int)$pview,
"canpostthreads" => (int)$pthreads,
"canpostreplys" => (int)$preplies,
"canpostpolls" => (int)$ppolls,
);
foreach($permission_fields as $field => $value)
{
if(array_key_exists($field, $insertquery))
{
continue;
}
$insertquery[$db->escape_string($field)] = (int)$existing_permissions[$field];
}
$db->insert_query("forumpermissions", $insertquery);
}
}
$cache->update_forumpermissions();
}
/**
* Checks if a particular user has the necessary permissions to access a particular page.
*
* @param array $action Array containing module and action to check for
* @param bool $error
* @return bool
*/
function check_admin_permissions($action, $error = true)
{
global $mybb, $page, $lang, $modules_dir;
if(is_super_admin($mybb->user['uid']))
{
return true;
}
require_once $modules_dir."/".$action['module']."/module_meta.php";
if(function_exists($action['module']."_admin_permissions"))
{
$func = $action['module']."_admin_permissions";
$permissions = $func();
if($permissions['permissions'][$action['action']] && $mybb->admin['permissions'][$action['module']][$action['action']] != 1)
{
if($error)
{
$page->output_header($lang->access_denied);
$page->add_breadcrumb_item($lang->access_denied, "index.php?module=home-index");
$page->output_error("<b>{$lang->access_denied}</b><ul><li style=\"list-style-type: none;\">{$lang->access_denied_desc}</li></ul>");
$page->output_footer();
exit;
}
else
{
return false;
}
}
}
return true;
}
/**
* Fetches the list of administrator permissions for a particular user or group
*
* @param int $get_uid The user ID to fetch permissions for
* @param int $get_gid The (optional) group ID to fetch permissions for
* @return array Array of permissions for specified user or group
*/
function get_admin_permissions($get_uid=0, $get_gid=0)
{
global $db, $mybb;
// Set UID and GID if none
$uid = $get_uid;
$gid = $get_gid;
$gid_array = array();
if($uid === 0)
{
$uid = $mybb->user['uid'];
}
if(!$gid)
{
// Prepare user's groups since the group isn't specified
$gid_array[] = (-1) * (int)$mybb->user['usergroup'];
if($mybb->user['additionalgroups'])
{
$additional_groups = explode(',', $mybb->user['additionalgroups']);
if(!empty($additional_groups))
{
// Make sure gids are negative
foreach($additional_groups as $g)
{
$gid_array[] = (-1) * abs($g);
}
}
}
}
else
{
// Group is specified
// Make sure gid is negative
$gid_array[] = (-1) * abs($gid);
}
// What are we trying to find?
if($get_gid && !$get_uid)
{
// A group only
$options = array(
"order_by" => "uid",
"order_dir" => "ASC",
"limit" => "1"
);
$query = $db->simple_select("adminoptions", "permissions", "(uid='-{$get_gid}' OR uid='0') AND permissions != ''", $options);
return my_unserialize($db->fetch_field($query, "permissions"));
}
else
{
// A user and/or group
$options = array(
"order_by" => "uid",
"order_dir" => "DESC"
);
// Prepare user's groups into SQL format
$group_sql = '';
foreach($gid_array as $gid)
{
$group_sql .= " OR uid='{$gid}'";
}
$perms_group = array();
$query = $db->simple_select("adminoptions", "permissions, uid", "(uid='{$uid}'{$group_sql}) AND permissions != ''", $options);
while($perm = $db->fetch_array($query))
{
$perm['permissions'] = my_unserialize($perm['permissions']);
// Sorting out which permission is which
if($perm['uid'] > 0)
{
$perms_user = $perm;
return $perms_user['permissions'];
}
elseif($perm['uid'] < 0)
{
$perms_group[] = $perm['permissions'];
}
else
{
$perms_def = $perm['permissions'];
}
}
// Figure out group permissions...ugh.
foreach($perms_group as $gperms)
{
if(!isset($final_group_perms))
{
// Use this group as the base for admin group permissions
$final_group_perms = $gperms;
continue;
}
// Loop through each specific permission to find the highest permission
foreach($gperms as $perm_name => $perm_value)
{
if($final_group_perms[$perm_name] != '1' && $perm_value == '1')
{
$final_group_perms[$perm_name] = '1';
}
}
}
// Send specific user, or group permissions before default.
// If user's permission are explicitly set, they've already been returned above.
if(isset($final_group_perms))
{
return $final_group_perms;
}
else
{
return $perms_def;
}
}
}
/**
* Fetch the iconv/mb encoding for a particular MySQL encoding
*
* @param string $mysql_encoding The MySQL encoding
* @return string The iconv/mb encoding
*/
function fetch_iconv_encoding($mysql_encoding)
{
$mysql_encoding = explode("_", $mysql_encoding);
switch($mysql_encoding[0])
{
case "utf8":
return "utf-8";
break;
case "latin1":
return "iso-8859-1";
break;
default:
return $mysql_encoding[0];
}
}
/**
* Adds/Updates a Page/Tab to the permissions array in the adminoptions table
*
* @param string $tab The name of the tab that is being affected
* @param string $page The name of the page being affected (optional - if not specified, will affect everything under the specified tab)
* @param integer $default Default permissions for the page (1 for allowed - 0 for disallowed - -1 to remove)
*/
function change_admin_permission($tab, $page="", $default=1)
{
global $db;
$query = $db->simple_select("adminoptions", "uid, permissions", "permissions != ''");
while($adminoption = $db->fetch_array($query))
{
$adminoption['permissions'] = my_unserialize($adminoption['permissions']);
if($default == -1)
{
if(!empty($page))
{
unset($adminoption['permissions'][$tab][$page]);
}
else
{
unset($adminoption['permissions'][$tab]);
}
}
else
{
if(!empty($page))
{
if($adminoption['uid'] == 0)
{
$adminoption['permissions'][$tab][$page] = 0;
}
else
{
$adminoption['permissions'][$tab][$page] = $default;
}
}
else
{
if($adminoption['uid'] == 0)
{
$adminoption['permissions'][$tab]['tab'] = 0;
}
else
{
$adminoption['permissions'][$tab]['tab'] = $default;
}
}
}
$db->update_query("adminoptions", array('permissions' => $db->escape_string(my_serialize($adminoption['permissions']))), "uid='{$adminoption['uid']}'");
}
}
/**
* Checks if we have had too many attempts at logging into the ACP
*
* @param integer $uid The uid of the admin to check
* @param boolean $return_num Return an array of the number of attempts and expiry time? (default false)
* @return mixed Return an array if the second parameter is true, boolean otherwise.
*/
function login_attempt_check_acp($uid=0, $return_num=false)
{
global $db, $mybb;
$attempts['loginattempts'] = 0;
if($uid > 0)
{
$query = $db->simple_select("adminoptions", "loginattempts, loginlockoutexpiry", "uid='".(int)$uid."'", 1);
$attempts = $db->fetch_array($query);
}
if($attempts['loginattempts'] <= 0)
{
return false;
}
if($mybb->settings['maxloginattempts'] > 0 && $attempts['loginattempts'] >= $mybb->settings['maxloginattempts'])
{
// Has the expiry dateline been set yet?
if($attempts['loginlockoutexpiry'] == 0 && $return_num == false)
{
$db->update_query("adminoptions", array("loginlockoutexpiry" => TIME_NOW+((int)$mybb->settings['loginattemptstimeout']*60)), "uid='".(int)$uid."'");
}
// Are we returning the # of login attempts?
if($return_num == true)
{
return $attempts;
}
// Otherwise are we still locked out?
else if($attempts['loginlockoutexpiry'] > TIME_NOW)
{
return true;
}
}
return false;
}
/**
* Checks whether the administrator is on a mobile device
*
* @param string $useragent The useragent to be checked
* @return boolean A true/false depending on if the administrator is on a mobile
*/
function is_mobile($useragent)
{
return preg_match("/(android|avantgo|blackberry|bolt|boost|cricket|docomo|fone|hiptop|mini|mobi|palm|phone|pie|tablet|up\.browser|up\.link|webos|wos)/i", $useragent);
}
/**
* Checks whether there are any 'security' issues in templates via complex syntax
*
* @param string $template The template to be scanned
* @return boolean A true/false depending on if an issue was detected
*/
function check_template($template)
{
// Check to see if our database password is in the template
if(preg_match('#\$config\[(([\'|"]database[\'|"])|([^\'"].*?))\]\[(([\'|"](database|hostname|password|table_prefix|username)[\'|"])|([^\'"].*?))\]#i', $template))
{
return true;
}
// System calls via backtick
if(preg_match('#\$\s*\{#', $template))
{
return true;
}
// Any other malicious acts?
// Courtesy of ZiNgA BuRgA
if(preg_match("~\\{\\$.+?\\}~s", preg_replace('~\\{\\$+[a-zA-Z_][a-zA-Z_0-9]*((?:-\\>|\\:\\:)\\$*[a-zA-Z_][a-zA-Z_0-9]*|\\[\s*\\$*([\'"]?)[a-zA-Z_ 0-9 ]+\\2\\]\s*)*\\}~', '', $template)))
{
return true;
}
return false;
}
/**
* Provides a function to entirely delete a user's posts, and find the threads attached to them
*
* @param integer $uid The uid of the user
* @param int $date A UNIX timestamp to delete posts that are older
* @return array An array of threads to delete, threads/forums to recount
*/
function delete_user_posts($uid, $date)
{
global $db;
$uid = (int)$uid;
// Build an array of posts to delete
$postcache = array();
$query = $db->simple_select("posts", "pid", "uid = '".$uid."' AND dateline < '".$date."'");
while($post = $db->fetch_array($query))
{
$postcache[] = $post['pid'];
}
if(!$db->num_rows($query))
{
return false;
}
elseif(!empty($postcache))
{
// Let's start deleting posts
$user_posts = implode(",", $postcache);
$query = $db->query("
SELECT p.pid, p.visible, f.usepostcounts, t.tid AS thread, t.firstpost, t.fid AS forum
FROM ".TABLE_PREFIX."posts p
LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=p.fid)
LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid)
WHERE p.pid IN ({$user_posts})
");
$post_count = 0; // Collect the post number to deduct from the user's postcount
$thread_list = array();
$forum_list = array();
$delete_thread_list = array();
if(!$db->num_rows($query))
{
return false;
}
else
{
while($post = $db->fetch_array($query))
{
if($post['usepostcounts'] != 0 && $post['visible'] != 0)
{
++$post_count;
}
if($post['pid'] == $post['firstpost'])
{
$delete_thread_list[] = $post['thread'];
}
if(!in_array($post['thread'], $thread_list) && !in_array($post['thread'], $delete_thread_list))
{
$thread_list[] = $post['thread']; // Threads that have been affected by this action, that aren't marked to be deleted
}
if(!in_array($post['forum'], $forum_list))
{
$forum_list[] = $post['forum']; // Forums that have been affected, too
}
// Remove the attachments to this post, then delete the post
remove_attachments($post['pid']);
$db->delete_query("posts", "pid = '".$post['pid']."'");
$db->delete_query("pollvotes", "pid = '".$post['pid']."'"); // Delete pollvotes attached to this post
}
$db->update_query("users", array("postnum" => "postnum-".$post_count.""), "uid='".$uid."'", 1, true);
$to_return = array(
'to_delete' => $delete_thread_list,
'thread_update' => $thread_list,
'forum_update' => $forum_list
);
return $to_return;
}
}
}
/**
* Prints a selection JavaScript code for selectable groups/forums fields.
*/
function print_selection_javascript()
{
static $already_printed = false;
if($already_printed)
{
return;
}
$already_printed = true;
echo "<script type=\"text/javascript\">
function checkAction(id)
{
var checked = '';
$('.'+id+'_forums_groups_check').each(function(e, val)
{
if($(this).prop('checked') == true)
{
checked = $(this).val();
}
});
$('.'+id+'_forums_groups').each(function(e)
{
$(this).hide();
});
if($('#'+id+'_forums_groups_'+checked))
{
$('#'+id+'_forums_groups_'+checked).show();
}
}
</script>";
}
if(!function_exists('array_column'))
{
function array_column($input, $column_key)
{
$values = array();
if(!is_array($input))
{
$input = array($input);
}
foreach($input as $val)
{
if(is_array($val) && isset($val[$column_key]))
{
$values[] = $val[$column_key];
}
elseif(is_object($val) && isset($val->$column_key))
{
$values[] = $val->$column_key;
}
}
return $values;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,674 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
/**
* Builds the "view management" interface allowing administrators to edit their custom designed "views"
*
* @param string $base_url The base URL to this instance of the view manager
* @param string $type The internal type identifier for this view
* @param array $fields Array of fields this view supports
* @param array $sort_options Array of possible sort options this view supports if any
* @param string $conditions_callback Optional callback function which generates list of "conditions" for this view
*/
function view_manager($base_url, $type, $fields, $sort_options=array(), $conditions_callback="")
{
global $mybb, $db, $page, $lang;
$sub_tabs['views'] = array(
'title' => $lang->views,
'link' => "{$base_url}&amp;action=views",
'description' => $lang->views_desc
);
$sub_tabs['create_view'] = array(
'title' => $lang->create_new_view,
'link' => "{$base_url}&amp;action=views&amp;do=add",
'description' => $lang->create_new_view_desc
);
$page->add_breadcrumb_item($lang->view_manager, 'index.php?module=user-users&amp;action=views');
// Lang strings should be in global lang file
if($mybb->input['do'] == "set_default")
{
$query = $db->simple_select("adminviews", "vid, uid, visibility", "vid='".$mybb->get_input('vid', MyBB::INPUT_INT)."'");
$admin_view = $db->fetch_array($query);
if(!$admin_view['vid'] || $admin_view['visibility'] == 1 && $mybb->user['uid'] != $admin_view['uid'])
{
flash_message($lang->error_invalid_admin_view, 'error');
admin_redirect($base_url."&action=views");
}
set_default_view($type, $admin_view['vid']);
flash_message($lang->succuss_view_set_as_default, 'success');
admin_redirect($base_url."&action=views");
}
if($mybb->input['do'] == "add")
{
if($mybb->request_method == "post")
{
if(!trim($mybb->input['title']))
{
$errors[] = $lang->error_missing_view_title;
}
if($mybb->input['fields_js'])
{
$mybb->input['fields'] = explode(",", $mybb->input['fields_js']);
}
if(is_array($mybb->input['fields']) && count($mybb->input['fields']) <= 0)
{
$errors[] = $lang->error_no_view_fields;
}
if($mybb->get_input('perpage', MyBB::INPUT_INT) <= 0)
{
$errors[] = $lang->error_invalid_view_perpage;
}
if(!in_array($mybb->input['sortby'], array_keys($sort_options)))
{
$errors[] = $lang->error_invalid_view_sortby;
}
if($mybb->input['sortorder'] != "asc" && $mybb->input['sortorder'] != "desc")
{
$errors[] = $lang->error_invalid_view_sortorder;
}
if($mybb->input['visibility'] == 0)
{
$mybb->input['visibility'] = 2;
}
if(!$errors)
{
$new_view = array(
"uid" => $mybb->user['uid'],
"title" => $db->escape_string($mybb->input['title']),
"type" => $type,
"visibility" => $mybb->get_input('visibility', MyBB::INPUT_INT),
"fields" => $db->escape_string(my_serialize($mybb->input['fields'])),
"conditions" => $db->escape_string(my_serialize($mybb->input['conditions'])),
"custom_profile_fields" => $db->escape_string(my_serialize($mybb->input['profile_fields'])),
"sortby" => $db->escape_string($mybb->input['sortby']),
"sortorder" => $db->escape_string($mybb->input['sortorder']),
"perpage" => $mybb->get_input('perpage', MyBB::INPUT_INT),
"view_type" => $db->escape_string($mybb->input['view_type'])
);
$vid = $db->insert_query("adminviews", $new_view);
if($mybb->input['isdefault'])
{
set_default_view($type, $vid);
}
flash_message($lang->success_view_created, "success");
admin_redirect($base_url."&vid={$vid}");
}
}
else
{
$mybb->input = array_merge($mybb->input, array('perpage' => 20));
}
// Write in our JS based field selector
$page->extra_header .= "<script src=\"jscripts/view_manager.js\" type=\"text/javascript\"></script>\n";
$page->add_breadcrumb_item($lang->create_new_view);
$page->output_header($lang->create_new_view);
$form = new Form($base_url."&amp;action=views&amp;do=add", "post");
$page->output_nav_tabs($sub_tabs, 'create_view');
// If we have any error messages, show them
if($errors)
{
$page->output_inline_error($errors);
}
$form_container = new FormContainer($lang->create_new_view);
$form_container->output_row($lang->title." <em>*</em>", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title');
if($mybb->input['visibility'] == 2)
{
$visibility_public_checked = true;
}
else
{
$visibility_private_checked = true;
}
$visibility_options = array(
$form->generate_radio_button("visibility", "1", "<strong>{$lang->private}</strong> - {$lang->private_desc}", array("checked" => $visibility_private_checked)),
$form->generate_radio_button("visibility", "2", "<strong>{$lang->public}</strong> - {$lang->public_desc}", array("checked" => $visibility_public_checked))
);
$form_container->output_row($lang->visibility, "", implode("<br />", $visibility_options));
$form_container->output_row($lang->set_as_default_view, "", $form->generate_yes_no_radio("isdefault", $mybb->input['isdefault'], array('yes' => 1, 'no' => 0)));
if(count($sort_options) > 0)
{
$sort_directions = array(
"asc" => $lang->ascending,
"desc" => $lang->descending
);
$form_container->output_row($lang->sort_results_by, "", $form->generate_select_box('sortby', $sort_options, $mybb->input['sortby'], array('id' => 'sortby'))." {$lang->in} ".$form->generate_select_box('sortorder', $sort_directions, $mybb->input['sortorder'], array('id' => 'sortorder')), 'sortby');
}
$form_container->output_row($lang->results_per_page, "", $form->generate_numeric_field('perpage', $mybb->input['perpage'], array('id' => 'perpage', 'min' => 1)), 'perpage');
if($type == "user")
{
$form_container->output_row($lang->display_results_as, "", $form->generate_radio_button('view_type', 'table', $lang->table, array('checked' => ($mybb->input['view_type'] != "card" ? true : false)))."<br />".$form->generate_radio_button('view_type', 'card', $lang->business_card, array('checked' => ($mybb->input['view_type'] == "card" ? true : false))));
}
$form_container->end();
$field_select .= "<div class=\"view_fields\">\n";
$field_select .= "<div class=\"enabled\"><div class=\"fields_title\">{$lang->enabled}</div><ul id=\"fields_enabled\">\n";
if(is_array($mybb->input['fields']))
{
foreach($mybb->input['fields'] as $field)
{
if($fields[$field])
{
$field_select .= "<li id=\"field-{$field}\">&#149; {$fields[$field]['title']}</li>";
$active[$field] = 1;
}
}
}
$field_select .= "</ul></div>\n";
$field_select .= "<div class=\"disabled\"><div class=\"fields_title\">{$lang->disabled}</div><ul id=\"fields_disabled\">\n";
foreach($fields as $key => $field)
{
if($active[$key])
{
continue;
}
$field_select .= "<li id=\"field-{$key}\">&#149; {$field['title']}</li>";
}
$field_select .= "</div></ul>\n";
$field_select .= $form->generate_hidden_field("fields_js", @implode(",", @array_keys($active)), array('id' => 'fields_js'));
$field_select = str_replace("'", "\\'", $field_select);
$field_select = str_replace("\n", "", $field_select);
$field_select = "<script type=\"text/javascript\">
//<![CDATA[
document.write('".str_replace("/", "\/", $field_select)."');
//]]>
</script>\n";
foreach($fields as $key => $field)
{
$field_options[$key] = $field['title'];
}
$field_select .= "<noscript>".$form->generate_select_box('fields[]', $field_options, $mybb->input['fields'], array('id' => 'fields', 'multiple' => true))."</noscript>\n";
$form_container = new FormContainer($lang->fields_to_show);
$form_container->output_row($lang->fields_to_show_desc, $description, $field_select);
$form_container->end();
// Build the search conditions
if(function_exists($conditions_callback))
{
$conditions_callback($mybb->input, $form);
}
$buttons[] = $form->generate_submit_button($lang->save_view);
$form->output_submit_wrapper($buttons);
$form->end();
$page->output_footer();
}
else if($mybb->input['do'] == "edit")
{
$query = $db->simple_select("adminviews", "*", "vid='".$mybb->get_input('vid', MyBB::INPUT_INT)."'");
$admin_view = $db->fetch_array($query);
// Does the view not exist?
if(!$admin_view['vid'] || $admin_view['visibility'] == 1 && $mybb->user['uid'] != $admin_view['uid'])
{
flash_message($lang->error_invalid_admin_view, 'error');
admin_redirect($base_url."&action=views");
}
if($mybb->request_method == "post")
{
if(!trim($mybb->input['title']))
{
$errors[] = $lang->error_missing_view_title;
}
if($mybb->input['fields_js'])
{
$mybb->input['fields'] = explode(",", $mybb->input['fields_js']);
}
if(is_array($mybb->input['fields']) && count($mybb->input['fields']) <= 0)
{
$errors[] = $lang->error_no_view_fields;
}
if($mybb->get_input('perpage', MyBB::INPUT_INT) <= 0)
{
$errors[] = $lang->error_invalid_view_perpage;
}
if(!in_array($mybb->input['sortby'], array_keys($sort_options)))
{
$errors[] = $lang->error_invalid_view_sortby;
}
if($mybb->input['sortorder'] != "asc" && $mybb->input['sortorder'] != "desc")
{
$errors[] = $lang->error_invalid_view_sortorder;
}
if($mybb->input['visibility'] == 0)
{
$mybb->input['visibility'] = 2;
}
if(!$errors)
{
$updated_view = array(
"title" => $db->escape_string($mybb->input['title']),
"type" => $type,
"visibility" => $mybb->get_input('visibility', MyBB::INPUT_INT),
"fields" => $db->escape_string(my_serialize($mybb->input['fields'])),
"conditions" => $db->escape_string(my_serialize($mybb->input['conditions'])),
"custom_profile_fields" => $db->escape_string(my_serialize($mybb->input['profile_fields'])),
"sortby" => $db->escape_string($mybb->input['sortby']),
"sortorder" => $db->escape_string($mybb->input['sortorder']),
"perpage" => $mybb->get_input('perpage', MyBB::INPUT_INT),
"view_type" => $db->escape_string($mybb->input['view_type'])
);
$db->update_query("adminviews", $updated_view, "vid='{$admin_view['vid']}'");
if($mybb->input['isdefault'])
{
set_default_view($type, $admin_view['vid']);
}
flash_message($lang->success_view_updated, "success");
admin_redirect($base_url."&vid={$admin_view['vid']}");
}
}
// Write in our JS based field selector
$page->extra_header .= "<script src=\"jscripts/view_manager.js\" type=\"text/javascript\"></script>\n";
$page->add_breadcrumb_item($lang->edit_view);
$page->output_header($lang->edit_view);
$form = new Form($base_url."&amp;action=views&amp;do=edit&amp;vid={$admin_view['vid']}", "post");
$sub_tabs = array();
$sub_tabs['edit_view'] = array(
'title' => $lang->edit_view,
'link' => $base_url."&amp;action=views&amp;do=edit&amp;vid={$admin_view['vid']}",
'description' => $lang->edit_view_desc
);
$page->output_nav_tabs($sub_tabs, 'edit_view');
// If we have any error messages, show them
if($errors)
{
$page->output_inline_error($errors);
}
else
{
$admin_view['conditions'] = my_unserialize($admin_view['conditions']);
$admin_view['fields'] = my_unserialize($admin_view['fields']);
$admin_view['profile_fields'] = my_unserialize($admin_view['custom_profile_fields']);
$mybb->input = array_merge($mybb->input, $admin_view);
$mybb->input['isdefault'] = 0;
$default_view = fetch_default_view($type);
if($default_view == $admin_view['vid'])
{
$mybb->input['isdefault'] = 1;
}
}
$form_container = new FormContainer($lang->edit_view);
$form_container->output_row($lang->view." <em>*</em>", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title');
if($mybb->input['visibility'] == 2)
{
$visibility_public_checked = true;
}
else
{
$visibility_private_checked = true;
}
$visibility_options = array(
$form->generate_radio_button("visibility", "1", "<strong>{$lang->private}</strong> - {$lang->private_desc}", array("checked" => $visibility_private_checked)),
$form->generate_radio_button("visibility", "2", "<strong>{$lang->public}</strong> - {$lang->public_desc}", array("checked" => $visibility_public_checked))
);
$form_container->output_row($lang->visibility, "", implode("<br />", $visibility_options));
$form_container->output_row($lang->set_as_default_view, "", $form->generate_yes_no_radio("isdefault", $mybb->input['isdefault'], array('yes' => 1, 'no' => 0)));
if(is_array($sort_options) && count($sort_options) > 0)
{
$sort_directions = array(
"asc" => $lang->ascending,
"desc" => $lang->descending
);
$form_container->output_row($lang->sort_results_by, "", $form->generate_select_box('sortby', $sort_options, $mybb->input['sortby'], array('id' => 'sortby'))." {$lang->in} ".$form->generate_select_box('sortorder', $sort_directions, $mybb->input['sortorder'], array('id' => 'sortorder')), 'sortby');
}
$form_container->output_row($lang->results_per_page, "", $form->generate_numeric_field('perpage', $mybb->input['perpage'], array('id' => 'perpage', 'min' => 1)), 'perpage');
if($type == "user")
{
$form_container->output_row($lang->display_results_as, "", $form->generate_radio_button('view_type', 'table', $lang->table, array('checked' => ($mybb->input['view_type'] != "card" ? true : false)))."<br />".$form->generate_radio_button('view_type', 'card', $lang->business_card, array('checked' => ($mybb->input['view_type'] == "card" ? true : false))));
}
$form_container->end();
$field_select .= "<div class=\"view_fields\">\n";
$field_select .= "<div class=\"enabled\"><div class=\"fields_title\">{$lang->enabled}</div><ul id=\"fields_enabled\">\n";
if(is_array($mybb->input['fields']))
{
foreach($mybb->input['fields'] as $field)
{
if($fields[$field])
{
$field_select .= "<li id=\"field-{$field}\">&#149; {$fields[$field]['title']}</li>";
$active[$field] = 1;
}
}
}
$field_select .= "</ul></div>\n";
$field_select .= "<div class=\"disabled\"><div class=\"fields_title\">{$lang->disabled}</div><ul id=\"fields_disabled\">\n";
if(is_array($fields))
{
foreach($fields as $key => $field)
{
if($active[$key])
{
continue;
}
$field_select .= "<li id=\"field-{$key}\">&#149; {$field['title']}</li>";
}
}
$field_select .= "</div></ul>\n";
$field_select .= $form->generate_hidden_field("fields_js", @implode(",", @array_keys($active)), array('id' => 'fields_js'));
$field_select = str_replace("'", "\\'", $field_select);
$field_select = str_replace("\n", "", $field_select);
$field_select = "<script type=\"text/javascript\">
//<![CDATA[
document.write('".str_replace("/", "\/", $field_select)."');
//]]></script>\n";
foreach($fields as $key => $field)
{
$field_options[$key] = $field['title'];
}
$field_select .= "<noscript>".$form->generate_select_box('fields[]', $field_options, $mybb->input['fields'], array('id' => 'fields', 'multiple' => true))."</noscript>\n";
$form_container = new FormContainer($lang->fields_to_show);
$form_container->output_row($lang->fields_to_show_desc, $description, $field_select);
$form_container->end();
// Build the search conditions
if(function_exists($conditions_callback))
{
$conditions_callback($mybb->input, $form);
}
$buttons[] = $form->generate_submit_button($lang->save_view);
$form->output_submit_wrapper($buttons);
$form->end();
$page->output_footer();
}
else if($mybb->input['do'] == "delete")
{
if($mybb->input['no'])
{
admin_redirect($base_url."&action=views");
}
$query = $db->simple_select("adminviews", "COUNT(vid) as views");
$views = $db->fetch_field($query, "views");
if($views == 0)
{
flash_message($lang->error_cannot_delete_view, 'error');
admin_redirect($base_url."&action=views");
}
$vid = $mybb->get_input('vid', MyBB::INPUT_INT);
$query = $db->simple_select("adminviews", "vid, uid, visibility", "vid = '{$vid}'");
$admin_view = $db->fetch_array($query);
if($vid == 1 || !$admin_view['vid'] || $admin_view['visibility'] == 1 && $mybb->user['uid'] != $admin_view['uid'])
{
flash_message($lang->error_invalid_view_delete, 'error');
admin_redirect($base_url."&action=views");
}
if($mybb->request_method == "post")
{
$db->delete_query("adminviews", "vid='{$admin_view['vid']}'");
flash_message($lang->success_view_deleted, 'success');
admin_redirect($base_url."&action=views");
}
else
{
$page->output_confirm_action($base_url."&amp;action=views&amp;do=delete&amp;vid={$admin_view['vid']}", $lang->confirm_view_deletion);
}
}
// Export views
else if($mybb->input['do'] == "export")
{
$xml = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?".">\n";
$xml = "<adminviews version=\"".$mybb->version_code."\" exported=\"".TIME_NOW."\">\n";
if($mybb->input['type'])
{
$type_where = "type='".$db->escape_string($mybb->input['type'])."'";
}
$query = $db->simple_select("adminviews", "*", $type_where);
while($admin_view = $db->fetch_array($query))
{
$fields = my_unserialize($admin_view['fields']);
$conditions = my_unserialize($admin_view['conditions']);
$admin_view['title'] = str_replace(']]>', ']]]]><![CDATA[>', $admin_view['title']);
$admin_view['sortby'] = str_replace(']]>', ']]]]><![CDATA[>', $admin_view['sortby']);
$admin_view['sortorder'] = str_replace(']]>', ']]]]><![CDATA[>', $admin_view['sortorder']);
$admin_view['view_type'] = str_replace(']]>', ']]]]><![CDATA[>', $admin_view['view_type']);
$xml .= "\t<view vid=\"{$admin_view['vid']}\" uid=\"{$admin_view['uid']}\" type=\"{$admin_view['type']}\" visibility=\"{$admin_view['visibility']}\">\n";
$xml .= "\t\t<title><![CDATA[{$admin_view['title']}]]></title>\n";
$xml .= "\t\t<fields>\n";
foreach($fields as $field)
{
$xml .= "\t\t\t<field name=\"{$field}\" />\n";
}
$xml .= "\t\t</fields>\n";
$xml .= "\t\t<conditions>\n";
foreach($conditions as $name => $condition)
{
if(!$conditions) continue;
if(is_array($condition))
{
$condition = my_serialize($condition);
$is_serialized = " is_serialized=\"1\"";
}
$condition = str_replace(']]>', ']]]]><![CDATA[>', $condition);
$xml .= "\t\t\t<condition name=\"{$name}\"{$is_serialized}><![CDATA[{$condition}]]></condition>\n";
}
$xml .= "\t\t</conditions>\n";
$xml .= "\t\t<sortby><![CDATA[{$admin_view['sortby']}]]></sortby>\n";
$xml .= "\t\t<sortorder><![CDATA[{$admin_view['sortorder']}]]></sortorder>\n";
$xml .= "\t\t<perpage><![CDATA[{$admin_view['perpage']}]]></perpage>\n";
$xml .= "\t\t<view_type><![CDATA[{$admin_view['view_type']}]]></view_type>\n";
$xml .= "\t</view>\n";
}
$xml .= "</adminviews>\n";
$mybb->settings['bbname'] = urlencode($mybb->settings['bbname']);
header("Content-disposition: filename=".$mybb->settings['bbname']."-views.xml");
header("Content-Length: ".my_strlen($xml));
header("Content-type: unknown/unknown");
header("Pragma: no-cache");
header("Expires: 0");
echo $xml;
exit;
}
// Generate a listing of all current views
else
{
$page->output_header($lang->view_manager);
$page->output_nav_tabs($sub_tabs, 'views');
$table = new Table;
$table->construct_header($lang->view);
$table->construct_header($lang->controls, array("class" => "align_center", "width" => 150));
$default_view = fetch_default_view($type);
$query = $db->simple_select("adminviews", "COUNT(vid) as views");
$views = $db->fetch_field($query, "views");
$query = $db->query("
SELECT v.*, u.username
FROM ".TABLE_PREFIX."adminviews v
LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=v.uid)
WHERE v.visibility='2' OR (v.visibility='1' AND v.uid='{$mybb->user['uid']}')
ORDER BY title
");
while($view = $db->fetch_array($query))
{
$created = "";
if($view['uid'] == 0)
{
$view_type = "default";
$default_class = "grey";
}
else if($view['visibility'] == 2)
{
$view_type = "group";
if($view['username'])
{
$username = htmlspecialchars_uni($view['username']);
$created = "<br /><small>{$lang->created_by} {$username}</small>";
}
}
else
{
$view_type = "user";
}
$default_add = '';
if($default_view == $view['vid'])
{
$default_add = " ({$lang->default})";
}
$title_string = "view_title_{$view['vid']}";
if($lang->$title_string)
{
$view['title'] = $lang->$title_string;
}
$table->construct_cell("<div class=\"float_right\"><img src=\"styles/{$page->style}/images/icons/{$view_type}.png\" title=\"".$lang->sprintf($lang->this_is_a_view, $view_type)."\" alt=\"{$view_type}\" /></div><div class=\"{$default_class}\"><strong><a href=\"{$base_url}&amp;action=views&amp;do=edit&amp;vid={$view['vid']}\" >{$view['title']}</a></strong>{$default_add}{$created}</div>");
$popup = new PopupMenu("view_{$view['vid']}", $lang->options);
$popup->add_item($lang->edit_view, "{$base_url}&amp;action=views&amp;do=edit&amp;vid={$view['vid']}");
if($view['vid'] != $default_view)
{
$popup->add_item($lang->set_as_default, "{$base_url}&amp;action=views&amp;do=set_default&amp;vid={$view['vid']}");
}
if($views > 1 && $view['vid'] != 1)
{
$popup->add_item($lang->delete_view, "{$base_url}&amp;action=views&amp;do=delete&amp;vid={$view['vid']}&amp;my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_view_deletion}')");
}
$controls = $popup->fetch();
$table->construct_cell($controls, array("class" => "align_center"));
$table->construct_row();
}
$table->output($lang->view);
echo <<<LEGEND
<br />
<fieldset>
<legend>{$lang->legend}</legend>
<img src="styles/{$page->style}/images/icons/default.png" alt="{$lang->default}" style="vertical-align: middle;" /> {$lang->default_view_desc}<br />
<img src="styles/{$page->style}/images/icons/group.png" alt="{$lang->public}" style="vertical-align: middle;" /> {$lang->public_view_desc}<br />
<img src="styles/{$page->style}/images/icons/user.png" alt="{$lang->private}" style="vertical-align: middle;" /> {$lang->private_view_desc}</fieldset>
LEGEND;
$page->output_footer();
}
}
function set_default_view($type, $vid)
{
global $mybb, $db;
$query = $db->simple_select("adminoptions", "defaultviews", "uid='{$mybb->user['uid']}'");
$default_views = my_unserialize($db->fetch_field($query, "defaultviews"));
if(!$db->num_rows($query))
{
$create = true;
}
$default_views[$type] = $vid;
$default_views = my_serialize($default_views);
$updated_admin = array("defaultviews" => $db->escape_string($default_views));
if($create == true)
{
$updated_admin['uid'] = $mybb->user['uid'];
$updated_admin['notes'] = '';
$updated_admin['permissions'] = '';
$db->insert_query("adminoptions", $updated_admin);
}
else
{
$db->update_query("adminoptions", $updated_admin, "uid='{$mybb->user['uid']}'");
}
}
/**
* @param string $type
*
* @return bool|array
*/
function fetch_default_view($type)
{
global $mybb, $db;
$query = $db->simple_select("adminoptions", "defaultviews", "uid='{$mybb->user['uid']}'");
$default_views = my_unserialize($db->fetch_field($query, "defaultviews"));
if(!is_array($default_views))
{
return false;
}
return $default_views[$type];
}

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,822 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
define("IN_MYBB", 1);
define("IN_ADMINCP", 1);
// Here you can change how much of an Admin CP IP address must match in a previous session for the user is validated (e.g. 3 means a.b.c need to match)
define("ADMIN_IP_SEGMENTS", 0);
define("ADMIN_IPV6_SEGMENTS", 0);
require_once dirname(dirname(__FILE__))."/inc/init.php";
$shutdown_queries = $shutdown_functions = array();
send_page_headers();
header('X-Frame-Options: SAMEORIGIN');
header('Referrer-Policy: no-referrer');
if(!isset($config['admin_dir']) || !file_exists(MYBB_ROOT.$config['admin_dir']."/inc/class_page.php"))
{
$config['admin_dir'] = basename(dirname(__FILE__));
}
define('MYBB_ADMIN_DIR', MYBB_ROOT.$config['admin_dir'].'/');
define('COPY_YEAR', my_date('Y', TIME_NOW));
require_once MYBB_ADMIN_DIR."inc/class_page.php";
require_once MYBB_ADMIN_DIR."inc/class_form.php";
require_once MYBB_ADMIN_DIR."inc/class_table.php";
require_once MYBB_ADMIN_DIR."inc/functions.php";
require_once MYBB_ROOT."inc/functions_user.php";
// Set cookie path to our admin dir temporarily, i.e. so that it affects the ACP only
$loc = get_current_location('', '', true);
$mybb->settings['cookiepath'] = substr($loc, 0, strrpos($loc, "/{$config['admin_dir']}/"))."/{$config['admin_dir']}/";
if(!isset($cp_language))
{
if(!file_exists(MYBB_ROOT."inc/languages/".$mybb->settings['cplanguage']."/admin/home_dashboard.lang.php"))
{
$mybb->settings['cplanguage'] = "english";
}
$lang->set_language($mybb->settings['cplanguage'], "admin");
}
// Load global language phrases
$lang->load("global");
$lang->load("messages", true);
if(function_exists('mb_internal_encoding') && !empty($lang->settings['charset']))
{
@mb_internal_encoding($lang->settings['charset']);
}
header("Content-type: text/html; charset={$lang->settings['charset']}");
$time = TIME_NOW;
$errors = null;
if(is_dir(MYBB_ROOT."install") && !file_exists(MYBB_ROOT."install/lock"))
{
$mybb->trigger_generic_error("install_directory");
}
$ip_address = get_ip();
unset($user);
// Load Admin CP style
if(!isset($cp_style))
{
if(!empty($mybb->settings['cpstyle']) && file_exists(MYBB_ADMIN_DIR."/styles/".$mybb->settings['cpstyle']."/main.css"))
{
$cp_style = $mybb->settings['cpstyle'];
}
else
{
$cp_style = "default";
}
}
$default_page = new DefaultPage;
$logged_out = false;
$fail_check = 0;
$post_verify = true;
foreach(array('action', 'do', 'module') as $input)
{
if(!isset($mybb->input[$input]))
{
$mybb->input[$input] = '';
}
}
if($mybb->input['action'] == "unlock")
{
$user = array();
$error = '';
$plugins->run_hooks("admin_unlock_start");
if($mybb->input['username'])
{
$user = get_user_by_username($mybb->input['username'], array('fields' => '*'));
if(!$user['uid'])
{
$error = $lang->error_invalid_username;
}
}
else if($mybb->input['uid'])
{
$user = get_user($mybb->input['uid']);
if(!$user['uid'])
{
$error = $lang->error_invalid_uid;
}
}
// Do we have the token? If so let's process it
if($mybb->input['token'] && $user['uid'])
{
$query = $db->simple_select("awaitingactivation", "COUNT(aid) AS num", "uid='".(int)$user['uid']."' AND code='".$db->escape_string($mybb->input['token'])."' AND type='l'");
$plugins->run_hooks("admin_unlock_end");
// If we're good to go
if($db->fetch_field($query, "num") > 0)
{
$db->delete_query("awaitingactivation", "uid='".(int)$user['uid']."' AND code='".$db->escape_string($mybb->input['token'])."' AND type='l'");
$db->update_query("adminoptions", array('loginlockoutexpiry' => 0, 'loginattempts' => 0), "uid='".(int)$user['uid']."'");
admin_redirect("index.php");
}
else
{
$error = $lang->error_invalid_token;
}
}
$default_page->show_lockout_unlock($error, 'error');
}
elseif($mybb->input['do'] == "login")
{
$plugins->run_hooks("admin_login");
// We have an adminsid cookie?
if(isset($mybb->cookies['adminsid']))
{
// Check admin session
$query = $db->simple_select("adminsessions", "sid", "sid='".$db->escape_string($mybb->cookies['adminsid'])."'");
$admin_session = $db->fetch_field($query, 'sid');
// Session found: redirect to index
if($admin_session)
{
admin_redirect("index.php");
}
}
require_once MYBB_ROOT."inc/datahandlers/login.php";
$loginhandler = new LoginDataHandler("get");
// Determine login method
$login_lang_string = $lang->error_invalid_username_password;
switch($mybb->settings['username_method'])
{
case 0: // Username only
$login_lang_string = $lang->sprintf($login_lang_string, $lang->login_username);
break;
case 1: // Email only
$login_lang_string = $lang->sprintf($login_lang_string, $lang->login_email);
break;
case 2: // Username and email
default:
$login_lang_string = $lang->sprintf($login_lang_string, $lang->login_username_and_password);
break;
}
// Validate PIN first
if(!empty($config['secret_pin']) && (empty($mybb->input['pin']) || $mybb->input['pin'] != $config['secret_pin']))
{
$login_user = get_user_by_username($mybb->input['username'], array('fields' => array('email', 'username')));
$plugins->run_hooks("admin_login_incorrect_pin");
if($login_user['uid'] > 0)
{
$db->update_query("adminoptions", array("loginattempts" => "loginattempts+1"), "uid='".(int)$login_user['uid']."'", '', true);
}
$loginattempts = login_attempt_check_acp($login_user['uid'], true);
// Have we attempted too many times?
if($loginattempts['loginattempts'] > 0)
{
// Have we set an expiry yet?
if($loginattempts['loginlockoutexpiry'] == 0)
{
$db->update_query("adminoptions", array("loginlockoutexpiry" => TIME_NOW+((int)$mybb->settings['loginattemptstimeout']*60)), "uid='".(int)$login_user['uid']."'");
}
// Did we hit lockout for the first time? Send the unlock email to the administrator
if($loginattempts['loginattempts'] == $mybb->settings['maxloginattempts'])
{
$db->delete_query("awaitingactivation", "uid='".(int)$login_user['uid']."' AND type='l'");
$lockout_array = array(
"uid" => $login_user['uid'],
"dateline" => TIME_NOW,
"code" => random_str(),
"type" => "l"
);
$db->insert_query("awaitingactivation", $lockout_array);
$subject = $lang->sprintf($lang->locked_out_subject, $mybb->settings['bbname']);
$message = $lang->sprintf($lang->locked_out_message, htmlspecialchars_uni($mybb->input['username']), $mybb->settings['bbname'], $mybb->settings['maxloginattempts'], $mybb->settings['bburl'], $mybb->config['admin_dir'], $lockout_array['code'], $lockout_array['uid']);
my_mail($login_user['email'], $subject, $message);
}
log_admin_action(array(
'type' => 'admin_locked_out',
'uid' => (int)$login_user['uid'],
'username' => $login_user['username'],
)
);
$default_page->show_lockedout();
}
else
{
$default_page->show_login($login_lang_string, "error");
}
}
$loginhandler->set_data(array(
'username' => $mybb->input['username'],
'password' => $mybb->input['password']
));
if($loginhandler->validate_login() == true)
{
$mybb->user = get_user($loginhandler->login_data['uid']);
}
if($mybb->user['uid'])
{
if(login_attempt_check_acp($mybb->user['uid']) == true)
{
log_admin_action(array(
'type' => 'admin_locked_out',
'uid' => (int)$mybb->user['uid'],
'username' => $mybb->user['username'],
)
);
$default_page->show_lockedout();
}
$plugins->run_hooks("admin_login_success");
$db->delete_query("adminsessions", "uid='{$mybb->user['uid']}'");
$sid = md5(random_str(50));
$useragent = $_SERVER['HTTP_USER_AGENT'];
if(my_strlen($useragent) > 200)
{
$useragent = my_substr($useragent, 0, 200);
}
// Create a new admin session for this user
$admin_session = array(
"sid" => $sid,
"uid" => $mybb->user['uid'],
"loginkey" => $mybb->user['loginkey'],
"ip" => $db->escape_binary(my_inet_pton(get_ip())),
"dateline" => TIME_NOW,
"lastactive" => TIME_NOW,
"data" => my_serialize(array()),
"useragent" => $db->escape_string($useragent),
);
$db->insert_query("adminsessions", $admin_session);
$admin_session['data'] = array();
// Only reset the loginattempts when we're really logged in and the user doesn't need to enter a 2fa code
$query = $db->simple_select("adminoptions", "authsecret", "uid='{$mybb->user['uid']}'");
$admin_options = $db->fetch_array($query);
if(empty($admin_options['authsecret']))
{
$db->update_query("adminoptions", array("loginattempts" => 0, "loginlockoutexpiry" => 0), "uid='{$mybb->user['uid']}'");
}
my_setcookie("adminsid", $sid, '', true, "lax");
my_setcookie('acploginattempts', 0);
$post_verify = false;
$mybb->request_method = "get";
if(!empty($mybb->input['module']))
{
// $query_string should contain the module
$query_string = '?module='.htmlspecialchars_uni($mybb->input['module']);
// Now we look for any paramters passed in $_SERVER['QUERY_STRING']
if($_SERVER['QUERY_STRING'])
{
$qstring = '?'.preg_replace('#adminsid=(.{32})#i', '', $_SERVER['QUERY_STRING']);
$qstring = str_replace('action=logout', '', $qstring);
$qstring = preg_replace('#&+#', '&', $qstring);
$qstring = str_replace('?&', '?', $qstring);
// So what do we do? We know that parameters are devided by ampersands
// That means we must get to work!
$parameters = explode('&', $qstring);
// Remove our first member if it's for the module
if(substr($parameters[0], 0, 8) == '?module=')
{
unset($parameters[0]);
}
foreach($parameters as $key => $param)
{
$params = explode("=", $param);
$query_string .= '&'.htmlspecialchars_uni($params[0])."=".htmlspecialchars_uni($params[1]);
}
}
admin_redirect("index.php".$query_string);
}
}
else
{
$login_user = get_user_by_username($mybb->input['username'], array('fields' => array('email', 'username')));
$plugins->run_hooks("admin_login_fail");
if($login_user['uid'] > 0)
{
$db->update_query("adminoptions", array("loginattempts" => "loginattempts+1"), "uid='".(int)$login_user['uid']."'", '', true);
}
$loginattempts = login_attempt_check_acp($login_user['uid'], true);
// Have we attempted too many times?
if($loginattempts['loginattempts'] > 0)
{
// Have we set an expiry yet?
if($loginattempts['loginlockoutexpiry'] == 0)
{
$db->update_query("adminoptions", array("loginlockoutexpiry" => TIME_NOW+((int)$mybb->settings['loginattemptstimeout']*60)), "uid='".(int)$login_user['uid']."'");
}
$plugins->run_hooks("admin_login_lockout");
// Did we hit lockout for the first time? Send the unlock email to the administrator
if($loginattempts['loginattempts'] == $mybb->settings['maxloginattempts'])
{
$db->delete_query("awaitingactivation", "uid='".(int)$login_user['uid']."' AND type='l'");
$lockout_array = array(
"uid" => $login_user['uid'],
"dateline" => TIME_NOW,
"code" => random_str(),
"type" => "l"
);
$db->insert_query("awaitingactivation", $lockout_array);
$subject = $lang->sprintf($lang->locked_out_subject, $mybb->settings['bbname']);
$message = $lang->sprintf($lang->locked_out_message, htmlspecialchars_uni($mybb->input['username']), $mybb->settings['bbname'], $mybb->settings['maxloginattempts'], $mybb->settings['bburl'], $mybb->config['admin_dir'], $lockout_array['code'], $lockout_array['uid']);
my_mail($login_user['email'], $subject, $message);
}
log_admin_action(array(
'type' => 'admin_locked_out',
'uid' => (int)$login_user['uid'],
'username' => $login_user['username'],
)
);
$default_page->show_lockedout();
}
$fail_check = 1;
}
}
else
{
// No admin session - show message on the login screen
if(!isset($mybb->cookies['adminsid']))
{
$login_message = "";
}
// Otherwise, check admin session
else
{
$query = $db->simple_select("adminsessions", "*", "sid='".$db->escape_string($mybb->cookies['adminsid'])."'");
$admin_session = $db->fetch_array($query);
// No matching admin session found - show message on login screen
if(!$admin_session['sid'])
{
$login_message = $lang->error_invalid_admin_session;
}
else
{
$admin_session['data'] = my_unserialize($admin_session['data']);
// Fetch the user from the admin session
$mybb->user = get_user($admin_session['uid']);
// Login key has changed - force logout
if(!$mybb->user['uid'] || $mybb->user['loginkey'] !== $admin_session['loginkey'])
{
unset($mybb->user);
}
else
{
// Admin CP sessions 2 hours old are expired
if($admin_session['lastactive'] < TIME_NOW-7200)
{
$login_message = $lang->error_admin_session_expired;
$db->delete_query("adminsessions", "sid='".$db->escape_string($mybb->cookies['adminsid'])."'");
unset($mybb->user);
}
// If IP matching is set - check IP address against the session IP
else if(ADMIN_IP_SEGMENTS > 0 && strpos($ip_address, ':') === false)
{
$exploded_ip = explode(".", $ip_address);
$exploded_admin_ip = explode(".", my_inet_ntop($admin_session['ip']));
$matches = 0;
$valid_ip = false;
for($i = 0; $i < ADMIN_IP_SEGMENTS; ++$i)
{
if($exploded_ip[$i] == $exploded_admin_ip[$i])
{
++$matches;
}
if($matches == ADMIN_IP_SEGMENTS)
{
$valid_ip = true;
break;
}
}
// IP doesn't match properly - show message on logon screen
if(!$valid_ip)
{
$login_message = $lang->error_invalid_ip;
unset($mybb->user);
}
}
else if(ADMIN_IPV6_SEGMENTS > 0 && strpos($ip_address, ':') !== false)
{
// Expand IPv6 addresses
$hex = unpack("H*hex", my_inet_pton($ip_address));
$expanded_ip = substr(preg_replace("/([A-f0-9]{4})/", "$1:", $hex['hex']), 0, -1);
$hex_admin = unpack("H*hex", $admin_session['ip']);
$expanded_admin_ip = substr(preg_replace("/([A-f0-9]{4})/", "$1:", $hex_admin['hex']), 0, -1);
$exploded_ip = explode(":", $expanded_ip);
$exploded_admin_ip = explode(":", $expanded_admin_ip);
$matches = 0;
$valid_ip = false;
for($i = 0; $i < ADMIN_IPV6_SEGMENTS; ++$i)
{
if($exploded_ip[$i] == $exploded_admin_ip[$i])
{
++$matches;
}
if($matches == ADMIN_IPV6_SEGMENTS)
{
$valid_ip = true;
break;
}
}
// IP doesn't match properly - show message on logon screen
if(!$valid_ip)
{
$login_message = $lang->error_invalid_ip;
unset($mybb->user);
}
}
}
}
}
}
if($mybb->input['action'] == "logout" && $mybb->user)
{
$plugins->run_hooks("admin_logout");
if(verify_post_check($mybb->input['my_post_key']))
{
$db->delete_query("adminsessions", "sid='".$db->escape_string($mybb->cookies['adminsid'])."'");
my_unsetcookie('adminsid');
$logged_out = true;
}
}
if(!isset($mybb->user['usergroup']))
{
$mybbgroups = 1;
}
else
{
$mybbgroups = $mybb->user['usergroup'].",".$mybb->user['additionalgroups'];
}
$mybb->usergroup = usergroup_permissions($mybbgroups);
$is_super_admin = is_super_admin($mybb->user['uid']);
if($mybb->usergroup['cancp'] != 1 && !$is_super_admin || !$mybb->user['uid'])
{
$uid = 0;
if(isset($mybb->user['uid']))
{
$uid = (int)$mybb->user['uid'];
}
$db->delete_query("adminsessions", "uid = '{$uid}'");
unset($mybb->user);
my_unsetcookie('adminsid');
}
if(!empty($mybb->user['uid']))
{
$query = $db->simple_select("adminoptions", "*", "uid='".$mybb->user['uid']."'");
$admin_options = $db->fetch_array($query);
// Update the session information in the DB
if($admin_session['sid'])
{
$db->update_query("adminsessions", array('lastactive' => TIME_NOW, 'ip' => $db->escape_binary(my_inet_pton(get_ip()))), "sid='".$db->escape_string($admin_session['sid'])."'");
}
// Fetch administrator permissions
$mybb->admin['permissions'] = get_admin_permissions($mybb->user['uid']);
}
// Do not have a valid Admin user, throw back to login page.
if(!isset($mybb->user['uid']) || $logged_out == true)
{
if($logged_out == true)
{
$default_page->show_login($lang->success_logged_out);
}
elseif($fail_check == 1)
{
$default_page->show_login($login_lang_string, "error");
}
else
{
// If we have this error while retreiving it from an AJAX request, then send back a nice error
if(isset($mybb->input['ajax']) && $mybb->input['ajax'] == 1)
{
echo json_encode(array("errors" => array("login")));
exit;
}
$default_page->show_login($login_message, "error");
}
}
// Time to check for Two-Factor Authentication
// First: are we trying to verify a code?
if($mybb->input['do'] == "do_2fa" && $mybb->request_method == "post")
{
// Test whether it's a recovery code
$recovery = false;
$codes = my_unserialize($admin_options['recovery_codes']);
if(!empty($codes) && in_array($mybb->get_input('code'), $codes))
{
$recovery = true;
$ncodes = array_diff($codes, array($mybb->input['code'])); // Removes our current code from the codes array
$db->update_query("adminoptions", array("recovery_codes" => $db->escape_string(my_serialize($ncodes))), "uid='{$mybb->user['uid']}'");
if(count($ncodes) == 0)
{
flash_message($lang->my2fa_no_codes, "error");
}
}
// Validate the code
require_once MYBB_ROOT."inc/3rdparty/2fa/GoogleAuthenticator.php";
$auth = new PHPGangsta_GoogleAuthenticator;
$test = $auth->verifyCode($admin_options['authsecret'], $mybb->get_input('code'));
// Either the code was okay or it was a recovery code
if($test === true || $recovery === true)
{
// Correct code -> session authenticated
$db->update_query("adminsessions", array("authenticated" => 1), "sid='".$db->escape_string($mybb->cookies['adminsid'])."'");
$admin_session['authenticated'] = 1;
$db->update_query("adminoptions", array("loginattempts" => 0, "loginlockoutexpiry" => 0), "uid='{$mybb->user['uid']}'");
my_setcookie('acploginattempts', 0);
// post would result in an authorization code mismatch error
$mybb->request_method = "get";
}
else
{
// Wrong code -> close session (aka logout)
$db->delete_query("adminsessions", "sid='".$db->escape_string($mybb->cookies['adminsid'])."'");
my_unsetcookie('adminsid');
// Now test whether we need to lock this guy completly
$db->update_query("adminoptions", array("loginattempts" => "loginattempts+1"), "uid='{$mybb->user['uid']}'", '', true);
$loginattempts = login_attempt_check_acp($mybb->user['uid'], true);
// Have we attempted too many times?
if($loginattempts['loginattempts'] > 0)
{
// Have we set an expiry yet?
if($loginattempts['loginlockoutexpiry'] == 0)
{
$db->update_query("adminoptions", array("loginlockoutexpiry" => TIME_NOW+((int)$mybb->settings['loginattemptstimeout']*60)), "uid='{$mybb->user['uid']}'");
}
// Did we hit lockout for the first time? Send the unlock email to the administrator
if($loginattempts['loginattempts'] == $mybb->settings['maxloginattempts'])
{
$db->delete_query("awaitingactivation", "uid='{$mybb->user['uid']}' AND type='l'");
$lockout_array = array(
"uid" => $mybb->user['uid'],
"dateline" => TIME_NOW,
"code" => random_str(),
"type" => "l"
);
$db->insert_query("awaitingactivation", $lockout_array);
$subject = $lang->sprintf($lang->locked_out_subject, $mybb->settings['bbname']);
$message = $lang->sprintf($lang->locked_out_message, htmlspecialchars_uni($mybb->user['username']), $mybb->settings['bbname'], $mybb->settings['maxloginattempts'], $mybb->settings['bburl'], $mybb->config['admin_dir'], $lockout_array['code'], $lockout_array['uid']);
my_mail($mybb->user['email'], $subject, $message);
}
log_admin_action(array(
'type' => 'admin_locked_out',
'uid' => $mybb->user['uid'],
'username' => $mybb->user['username'],
)
);
$default_page->show_lockedout();
}
// Still here? Show a custom login page
$default_page->show_login($lang->my2fa_failed, "error");
}
}
// Show our 2FA page
if(!empty($admin_options['authsecret']) && $admin_session['authenticated'] != 1)
{
$default_page->show_2fa();
}
// Now the user is fully authenticated setup their personal options
if(!empty($admin_options['cplanguage']) && file_exists(MYBB_ROOT."inc/languages/".$admin_options['cplanguage']."/admin/home_dashboard.lang.php"))
{
$cp_language = $admin_options['cplanguage'];
$lang->set_language($cp_language, "admin");
$lang->load("global"); // Reload global language vars
$lang->load("messages", true);
}
if(!empty($admin_options['cpstyle']) && file_exists(MYBB_ADMIN_DIR."/styles/{$admin_options['cpstyle']}/main.css"))
{
$cp_style = $admin_options['cpstyle'];
}
// Include the layout generation class overrides for this style
if(file_exists(MYBB_ADMIN_DIR."/styles/{$cp_style}/style.php"))
{
require_once MYBB_ADMIN_DIR."/styles/{$cp_style}/style.php";
}
// Check if any of the layout generation classes we can override exist in the style file
$classes = array(
"Page" => "DefaultPage",
"SidebarItem" => "DefaultSidebarItem",
"PopupMenu" => "DefaultPopupMenu",
"Table" => "DefaultTable",
"Form" => "DefaultForm",
"FormContainer" => "DefaultFormContainer"
);
foreach($classes as $style_name => $default_name)
{
// Style does not have this layout generation class, create it
if(!class_exists($style_name))
{
eval("class {$style_name} extends {$default_name} { }");
}
}
$page = new Page;
$page->style = $cp_style;
$page->add_breadcrumb_item($lang->home, "index.php");
// Begin dealing with the modules
$modules_dir = MYBB_ADMIN_DIR."modules";
$dir = opendir($modules_dir);
while(($module = readdir($dir)) !== false)
{
if(is_dir($modules_dir."/".$module) && !in_array($module, array(".", "..")) && file_exists($modules_dir."/".$module."/module_meta.php"))
{
require_once $modules_dir."/".$module."/module_meta.php";
// Need to always load it for admin permissions / quick access
$lang->load($module."_module_meta", false, true);
$has_permission = false;
if(function_exists($module."_admin_permissions"))
{
if(isset($mybb->admin['permissions'][$module]) || $is_super_admin == true)
{
$has_permission = true;
}
}
// This module doesn't support permissions
else
{
$has_permission = true;
}
// Do we have permissions to run this module (Note: home is accessible by all)
if($module == "home" || $has_permission == true)
{
$meta_function = $module."_meta";
$initialized = $meta_function();
if($initialized == true)
{
$modules[$module] = 1;
}
}
else
{
$modules[$module] = 0;
}
}
}
$modules = $plugins->run_hooks("admin_tabs", $modules);
closedir($dir);
if(strpos($mybb->input['module'], "/") !== false)
{
$current_module = explode("/", $mybb->input['module'], 2);
}
else
{
$current_module = explode("-", $mybb->input['module'], 2);
}
if(!isset($current_module[1]))
{
$current_module[1] = 'home';
}
if($mybb->input['module'] && isset($modules[$current_module[0]]))
{
$run_module = $current_module[0];
}
else
{
$run_module = "home";
}
$action_handler = $run_module."_action_handler";
$action_file = $action_handler($current_module[1]);
// Set our POST validation code here
$mybb->post_code = generate_post_check();
if($run_module != "home")
{
check_admin_permissions(array('module' => $page->active_module, 'action' => $page->active_action));
}
// Only POST actions with a valid post code can modify information. Here we check if the incoming request is a POST and if that key is valid.
$post_check_ignores = array(
"example/page" => array("action")
); // An array of modules/actions to ignore POST checks for.
if($mybb->request_method == "post")
{
if(in_array($mybb->input['module'], $post_check_ignores))
{
$k = array_search($mybb->input['module'], $post_check_ignores);
if(in_array($mybb->input['action'], $post_check_ignores[$k]))
{
$post_verify = false;
}
}
if($post_verify == true)
{
// If the post key does not match we switch the action to GET and set a message to show the user
if(!isset($mybb->input['my_post_key']) || $mybb->post_code !== $mybb->input['my_post_key'])
{
$mybb->request_method = "get";
$page->show_post_verify_error = true;
}
}
}
$lang->load("{$run_module}_{$page->active_action}", false, true);
$plugins->run_hooks("admin_load");
require $modules_dir."/".$run_module."/".$action_file;

View File

@@ -0,0 +1,23 @@
var AdminCP = {
init: function()
{
},
deleteConfirmation: function(element, message)
{
if(!element) return false;
confirmReturn = confirm(message);
if(confirmReturn == true)
{
form = $("<form />", { method: "post", action: element.href, style: "display: none;" });
$("body").append(form);
form.trigger('submit');
}
return false;
}
};
$(function()
{
AdminCP.init();
});

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (C) 2017 by Marijn Haverbeke <marijnh@gmail.com> and others
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,32 @@
.CodeMirror-dialog {
position: absolute;
left: 0; right: 0;
background: #1F4661;
z-index: 15;
padding: .1em .8em;
overflow: hidden;
color: #fff;
}
.CodeMirror-dialog-top {
border-bottom: 1px solid #3E7087;
top: 0;
}
.CodeMirror-dialog-bottom {
border-top: 1px solid #3E7087;
bottom: 0;
}
.CodeMirror-dialog input {
border: none;
outline: none;
background: transparent;
width: 20em;
color: inherit;
font-family: monospace;
}
.CodeMirror-dialog button {
font-size: 70%;
}

View File

@@ -0,0 +1,32 @@
.CodeMirror-dialog {
position: absolute;
left: 0; right: 0;
background: inherit;
z-index: 15;
padding: .1em .8em;
overflow: hidden;
color: inherit;
}
.CodeMirror-dialog-top {
border-bottom: 1px solid #eee;
top: 0;
}
.CodeMirror-dialog-bottom {
border-top: 1px solid #eee;
bottom: 0;
}
.CodeMirror-dialog input {
border: none;
outline: none;
background: transparent;
width: 20em;
color: inherit;
font-family: monospace;
}
.CodeMirror-dialog button {
font-size: 70%;
}

View File

@@ -0,0 +1,157 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// Open simple dialogs on top of an editor. Relies on dialog.css.
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
function dialogDiv(cm, template, bottom) {
var wrap = cm.getWrapperElement();
var dialog;
dialog = wrap.appendChild(document.createElement("div"));
if (bottom)
dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
else
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
if (typeof template == "string") {
dialog.innerHTML = template;
} else { // Assuming it's a detached DOM element.
dialog.appendChild(template);
}
return dialog;
}
function closeNotification(cm, newVal) {
if (cm.state.currentNotificationClose)
cm.state.currentNotificationClose();
cm.state.currentNotificationClose = newVal;
}
CodeMirror.defineExtension("openDialog", function(template, callback, options) {
if (!options) options = {};
closeNotification(this, null);
var dialog = dialogDiv(this, template, options.bottom);
var closed = false, me = this;
function close(newVal) {
if (typeof newVal == 'string') {
inp.value = newVal;
} else {
if (closed) return;
closed = true;
dialog.parentNode.removeChild(dialog);
me.focus();
if (options.onClose) options.onClose(dialog);
}
}
var inp = dialog.getElementsByTagName("input")[0], button;
if (inp) {
inp.focus();
if (options.value) {
inp.value = options.value;
if (options.selectValueOnOpen !== false) {
inp.select();
}
}
if (options.onInput)
CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);});
if (options.onKeyUp)
CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
CodeMirror.on(inp, "keydown", function(e) {
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {
inp.blur();
CodeMirror.e_stop(e);
close();
}
if (e.keyCode == 13) callback(inp.value, e);
});
if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
} else if (button = dialog.getElementsByTagName("button")[0]) {
CodeMirror.on(button, "click", function() {
close();
me.focus();
});
if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close);
button.focus();
}
return close;
});
CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
closeNotification(this, null);
var dialog = dialogDiv(this, template, options && options.bottom);
var buttons = dialog.getElementsByTagName("button");
var closed = false, me = this, blurring = 1;
function close() {
if (closed) return;
closed = true;
dialog.parentNode.removeChild(dialog);
me.focus();
}
buttons[0].focus();
for (var i = 0; i < buttons.length; ++i) {
var b = buttons[i];
(function(callback) {
CodeMirror.on(b, "click", function(e) {
CodeMirror.e_preventDefault(e);
close();
if (callback) callback(me);
});
})(callbacks[i]);
CodeMirror.on(b, "blur", function() {
--blurring;
setTimeout(function() { if (blurring <= 0) close(); }, 200);
});
CodeMirror.on(b, "focus", function() { ++blurring; });
}
});
/*
* openNotification
* Opens a notification, that can be closed with an optional timer
* (default 5000ms timer) and always closes on click.
*
* If a notification is opened while another is opened, it will close the
* currently opened one and open the new one immediately.
*/
CodeMirror.defineExtension("openNotification", function(template, options) {
closeNotification(this, close);
var dialog = dialogDiv(this, template, options && options.bottom);
var closed = false, doneTimer;
var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000;
function close() {
if (closed) return;
closed = true;
clearTimeout(doneTimer);
dialog.parentNode.removeChild(dialog);
}
CodeMirror.on(dialog, 'click', function(e) {
CodeMirror.e_preventDefault(e);
close();
});
if (duration)
doneTimer = setTimeout(close, duration);
return close;
});
});

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,105 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.registerHelper("fold", "brace", function(cm, start) {
var line = start.line, lineText = cm.getLine(line);
var tokenType;
function findOpening(openCh) {
for (var at = start.ch, pass = 0;;) {
var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1);
if (found == -1) {
if (pass == 1) break;
pass = 1;
at = lineText.length;
continue;
}
if (pass == 1 && found < start.ch) break;
tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));
if (!/^(comment|string)/.test(tokenType)) return found + 1;
at = found - 1;
}
}
var startToken = "{", endToken = "}", startCh = findOpening("{");
if (startCh == null) {
startToken = "[", endToken = "]";
startCh = findOpening("[");
}
if (startCh == null) return;
var count = 1, lastLine = cm.lastLine(), end, endCh;
outer: for (var i = line; i <= lastLine; ++i) {
var text = cm.getLine(i), pos = i == line ? startCh : 0;
for (;;) {
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
if (nextOpen < 0) nextOpen = text.length;
if (nextClose < 0) nextClose = text.length;
pos = Math.min(nextOpen, nextClose);
if (pos == text.length) break;
if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) {
if (pos == nextOpen) ++count;
else if (!--count) { end = i; endCh = pos; break outer; }
}
++pos;
}
}
if (end == null || line == end && endCh == startCh) return;
return {from: CodeMirror.Pos(line, startCh),
to: CodeMirror.Pos(end, endCh)};
});
CodeMirror.registerHelper("fold", "import", function(cm, start) {
function hasImport(line) {
if (line < cm.firstLine() || line > cm.lastLine()) return null;
var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
if (start.type != "keyword" || start.string != "import") return null;
// Now find closing semicolon, return its position
for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
var text = cm.getLine(i), semi = text.indexOf(";");
if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
}
}
var startLine = start.line, has = hasImport(startLine), prev;
if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1))
return null;
for (var end = has.end;;) {
var next = hasImport(end.line + 1);
if (next == null) break;
end = next.end;
}
return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end};
});
CodeMirror.registerHelper("fold", "include", function(cm, start) {
function hasInclude(line) {
if (line < cm.firstLine() || line > cm.lastLine()) return null;
var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
}
var startLine = start.line, has = hasInclude(startLine);
if (has == null || hasInclude(startLine - 1) != null) return null;
for (var end = startLine;;) {
var next = hasInclude(end + 1);
if (next == null) break;
++end;
}
return {from: CodeMirror.Pos(startLine, has + 1),
to: cm.clipPos(CodeMirror.Pos(end))};
});
});

View File

@@ -0,0 +1,59 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
return mode.blockCommentStart && mode.blockCommentEnd;
}, function(cm, start) {
var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;
if (!startToken || !endToken) return;
var line = start.line, lineText = cm.getLine(line);
var startCh;
for (var at = start.ch, pass = 0;;) {
var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1);
if (found == -1) {
if (pass == 1) return;
pass = 1;
at = lineText.length;
continue;
}
if (pass == 1 && found < start.ch) return;
if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) &&
(found == 0 || lineText.slice(found - endToken.length, found) == endToken ||
!/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) {
startCh = found + startToken.length;
break;
}
at = found - 1;
}
var depth = 1, lastLine = cm.lastLine(), end, endCh;
outer: for (var i = line; i <= lastLine; ++i) {
var text = cm.getLine(i), pos = i == line ? startCh : 0;
for (;;) {
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
if (nextOpen < 0) nextOpen = text.length;
if (nextClose < 0) nextClose = text.length;
pos = Math.min(nextOpen, nextClose);
if (pos == text.length) break;
if (pos == nextOpen) ++depth;
else if (!--depth) { end = i; endCh = pos; break outer; }
++pos;
}
}
if (end == null || line == end && endCh == startCh) return;
return {from: CodeMirror.Pos(line, startCh),
to: CodeMirror.Pos(end, endCh)};
});
});

View File

@@ -0,0 +1,152 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
function doFold(cm, pos, options, force) {
if (options && options.call) {
var finder = options;
options = null;
} else {
var finder = getOption(cm, options, "rangeFinder");
}
if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
var minSize = getOption(cm, options, "minFoldSize");
function getRange(allowFolded) {
var range = finder(cm, pos);
if (!range || range.to.line - range.from.line < minSize) return null;
var marks = cm.findMarksAt(range.from);
for (var i = 0; i < marks.length; ++i) {
if (marks[i].__isFold && force !== "fold") {
if (!allowFolded) return null;
range.cleared = true;
marks[i].clear();
}
}
return range;
}
var range = getRange(true);
if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) {
pos = CodeMirror.Pos(pos.line - 1, 0);
range = getRange(false);
}
if (!range || range.cleared || force === "unfold") return;
var myWidget = makeWidget(cm, options);
CodeMirror.on(myWidget, "mousedown", function(e) {
myRange.clear();
CodeMirror.e_preventDefault(e);
});
var myRange = cm.markText(range.from, range.to, {
replacedWith: myWidget,
clearOnEnter: getOption(cm, options, "clearOnEnter"),
__isFold: true
});
myRange.on("clear", function(from, to) {
CodeMirror.signal(cm, "unfold", cm, from, to);
});
CodeMirror.signal(cm, "fold", cm, range.from, range.to);
}
function makeWidget(cm, options) {
var widget = getOption(cm, options, "widget");
if (typeof widget == "string") {
var text = document.createTextNode(widget);
widget = document.createElement("span");
widget.appendChild(text);
widget.className = "CodeMirror-foldmarker";
} else if (widget) {
widget = widget.cloneNode(true)
}
return widget;
}
// Clumsy backwards-compatible interface
CodeMirror.newFoldFunction = function(rangeFinder, widget) {
return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };
};
// New-style interface
CodeMirror.defineExtension("foldCode", function(pos, options, force) {
doFold(this, pos, options, force);
});
CodeMirror.defineExtension("isFolded", function(pos) {
var marks = this.findMarksAt(pos);
for (var i = 0; i < marks.length; ++i)
if (marks[i].__isFold) return true;
});
CodeMirror.commands.toggleFold = function(cm) {
cm.foldCode(cm.getCursor());
};
CodeMirror.commands.fold = function(cm) {
cm.foldCode(cm.getCursor(), null, "fold");
};
CodeMirror.commands.unfold = function(cm) {
cm.foldCode(cm.getCursor(), null, "unfold");
};
CodeMirror.commands.foldAll = function(cm) {
cm.operation(function() {
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
cm.foldCode(CodeMirror.Pos(i, 0), null, "fold");
});
};
CodeMirror.commands.unfoldAll = function(cm) {
cm.operation(function() {
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold");
});
};
CodeMirror.registerHelper("fold", "combine", function() {
var funcs = Array.prototype.slice.call(arguments, 0);
return function(cm, start) {
for (var i = 0; i < funcs.length; ++i) {
var found = funcs[i](cm, start);
if (found) return found;
}
};
});
CodeMirror.registerHelper("fold", "auto", function(cm, start) {
var helpers = cm.getHelpers(start, "fold");
for (var i = 0; i < helpers.length; i++) {
var cur = helpers[i](cm, start);
if (cur) return cur;
}
});
var defaultOptions = {
rangeFinder: CodeMirror.fold.auto,
widget: "\u2194",
minFoldSize: 0,
scanUp: false,
clearOnEnter: true
};
CodeMirror.defineOption("foldOptions", null);
function getOption(cm, options, name) {
if (options && options[name] !== undefined)
return options[name];
var editorOptions = cm.options.foldOptions;
if (editorOptions && editorOptions[name] !== undefined)
return editorOptions[name];
return defaultOptions[name];
}
CodeMirror.defineExtension("foldOption", function(options, name) {
return getOption(this, options, name);
});
});

View File

@@ -0,0 +1,20 @@
.CodeMirror-foldmarker {
color: blue;
text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
font-family: arial;
line-height: .3;
cursor: pointer;
}
.CodeMirror-foldgutter {
width: .7em;
}
.CodeMirror-foldgutter-open,
.CodeMirror-foldgutter-folded {
cursor: pointer;
}
.CodeMirror-foldgutter-open:after {
content: "\25BE";
}
.CodeMirror-foldgutter-folded:after {
content: "\25B8";
}

View File

@@ -0,0 +1,146 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./foldcode"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./foldcode"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) {
cm.clearGutter(cm.state.foldGutter.options.gutter);
cm.state.foldGutter = null;
cm.off("gutterClick", onGutterClick);
cm.off("change", onChange);
cm.off("viewportChange", onViewportChange);
cm.off("fold", onFold);
cm.off("unfold", onFold);
cm.off("swapDoc", onChange);
}
if (val) {
cm.state.foldGutter = new State(parseOptions(val));
updateInViewport(cm);
cm.on("gutterClick", onGutterClick);
cm.on("change", onChange);
cm.on("viewportChange", onViewportChange);
cm.on("fold", onFold);
cm.on("unfold", onFold);
cm.on("swapDoc", onChange);
}
});
var Pos = CodeMirror.Pos;
function State(options) {
this.options = options;
this.from = this.to = 0;
}
function parseOptions(opts) {
if (opts === true) opts = {};
if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
return opts;
}
function isFolded(cm, line) {
var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));
for (var i = 0; i < marks.length; ++i)
if (marks[i].__isFold && marks[i].find().from.line == line) return marks[i];
}
function marker(spec) {
if (typeof spec == "string") {
var elt = document.createElement("div");
elt.className = spec + " CodeMirror-guttermarker-subtle";
return elt;
} else {
return spec.cloneNode(true);
}
}
function updateFoldInfo(cm, from, to) {
var opts = cm.state.foldGutter.options, cur = from;
var minSize = cm.foldOption(opts, "minFoldSize");
var func = cm.foldOption(opts, "rangeFinder");
cm.eachLine(from, to, function(line) {
var mark = null;
if (isFolded(cm, cur)) {
mark = marker(opts.indicatorFolded);
} else {
var pos = Pos(cur, 0);
var range = func && func(cm, pos);
if (range && range.to.line - range.from.line >= minSize)
mark = marker(opts.indicatorOpen);
}
cm.setGutterMarker(line, opts.gutter, mark);
++cur;
});
}
function updateInViewport(cm) {
var vp = cm.getViewport(), state = cm.state.foldGutter;
if (!state) return;
cm.operation(function() {
updateFoldInfo(cm, vp.from, vp.to);
});
state.from = vp.from; state.to = vp.to;
}
function onGutterClick(cm, line, gutter) {
var state = cm.state.foldGutter;
if (!state) return;
var opts = state.options;
if (gutter != opts.gutter) return;
var folded = isFolded(cm, line);
if (folded) folded.clear();
else cm.foldCode(Pos(line, 0), opts.rangeFinder);
}
function onChange(cm) {
var state = cm.state.foldGutter;
if (!state) return;
var opts = state.options;
state.from = state.to = 0;
clearTimeout(state.changeUpdate);
state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
}
function onViewportChange(cm) {
var state = cm.state.foldGutter;
if (!state) return;
var opts = state.options;
clearTimeout(state.changeUpdate);
state.changeUpdate = setTimeout(function() {
var vp = cm.getViewport();
if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
updateInViewport(cm);
} else {
cm.operation(function() {
if (vp.from < state.from) {
updateFoldInfo(cm, vp.from, state.from);
state.from = vp.from;
}
if (vp.to > state.to) {
updateFoldInfo(cm, state.to, vp.to);
state.to = vp.to;
}
});
}
}, opts.updateViewportTimeSpan || 400);
}
function onFold(cm, from) {
var state = cm.state.foldGutter;
if (!state) return;
var line = from.line;
if (line >= state.from && line < state.to)
updateFoldInfo(cm, line, line + 1);
}
});

View File

@@ -0,0 +1,48 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
function lineIndent(cm, lineNo) {
var text = cm.getLine(lineNo)
var spaceTo = text.search(/\S/)
if (spaceTo == -1 || /\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, spaceTo + 1))))
return -1
return CodeMirror.countColumn(text, null, cm.getOption("tabSize"))
}
CodeMirror.registerHelper("fold", "indent", function(cm, start) {
var myIndent = lineIndent(cm, start.line)
if (myIndent < 0) return
var lastLineInFold = null
// Go through lines until we find a line that definitely doesn't belong in
// the block we're folding, or to the end.
for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
var indent = lineIndent(cm, i)
if (indent == -1) {
} else if (indent > myIndent) {
// Lines with a greater indent are considered part of the block.
lastLineInFold = i;
} else {
// If this line has non-space, non-comment content, and is
// indented less or equal to the start line, it is the start of
// another block.
break;
}
}
if (lastLineInFold) return {
from: CodeMirror.Pos(start.line, cm.getLine(start.line).length),
to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
};
});
});

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,49 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.registerHelper("fold", "markdown", function(cm, start) {
var maxDepth = 100;
function isHeader(lineNo) {
var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0));
return tokentype && /\bheader\b/.test(tokentype);
}
function headerLevel(lineNo, line, nextLine) {
var match = line && line.match(/^#+/);
if (match && isHeader(lineNo)) return match[0].length;
match = nextLine && nextLine.match(/^[=\-]+\s*$/);
if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2;
return maxDepth;
}
var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1);
var level = headerLevel(start.line, firstLine, nextLine);
if (level === maxDepth) return undefined;
var lastLineNo = cm.lastLine();
var end = start.line, nextNextLine = cm.getLine(end + 2);
while (end < lastLineNo) {
if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break;
++end;
nextLine = nextNextLine;
nextNextLine = cm.getLine(end + 2);
}
return {
from: CodeMirror.Pos(start.line, firstLine.length),
to: CodeMirror.Pos(end, cm.getLine(end).length)
};
});
});

View File

@@ -0,0 +1,182 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var Pos = CodeMirror.Pos;
function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
function Iter(cm, line, ch, range) {
this.line = line; this.ch = ch;
this.cm = cm; this.text = cm.getLine(line);
this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine();
this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine();
}
function tagAt(iter, ch) {
var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
return type && /\btag\b/.test(type);
}
function nextLine(iter) {
if (iter.line >= iter.max) return;
iter.ch = 0;
iter.text = iter.cm.getLine(++iter.line);
return true;
}
function prevLine(iter) {
if (iter.line <= iter.min) return;
iter.text = iter.cm.getLine(--iter.line);
iter.ch = iter.text.length;
return true;
}
function toTagEnd(iter) {
for (;;) {
var gt = iter.text.indexOf(">", iter.ch);
if (gt == -1) { if (nextLine(iter)) continue; else return; }
if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
var lastSlash = iter.text.lastIndexOf("/", gt);
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
iter.ch = gt + 1;
return selfClose ? "selfClose" : "regular";
}
}
function toTagStart(iter) {
for (;;) {
var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;
if (lt == -1) { if (prevLine(iter)) continue; else return; }
if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
xmlTagStart.lastIndex = lt;
iter.ch = lt;
var match = xmlTagStart.exec(iter.text);
if (match && match.index == lt) return match;
}
}
function toNextTag(iter) {
for (;;) {
xmlTagStart.lastIndex = iter.ch;
var found = xmlTagStart.exec(iter.text);
if (!found) { if (nextLine(iter)) continue; else return; }
if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
iter.ch = found.index + found[0].length;
return found;
}
}
function toPrevTag(iter) {
for (;;) {
var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;
if (gt == -1) { if (prevLine(iter)) continue; else return; }
if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
var lastSlash = iter.text.lastIndexOf("/", gt);
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
iter.ch = gt + 1;
return selfClose ? "selfClose" : "regular";
}
}
function findMatchingClose(iter, tag) {
var stack = [];
for (;;) {
var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
if (!next || !(end = toTagEnd(iter))) return;
if (end == "selfClose") continue;
if (next[1]) { // closing tag
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
stack.length = i;
break;
}
if (i < 0 && (!tag || tag == next[2])) return {
tag: next[2],
from: Pos(startLine, startCh),
to: Pos(iter.line, iter.ch)
};
} else { // opening tag
stack.push(next[2]);
}
}
}
function findMatchingOpen(iter, tag) {
var stack = [];
for (;;) {
var prev = toPrevTag(iter);
if (!prev) return;
if (prev == "selfClose") { toTagStart(iter); continue; }
var endLine = iter.line, endCh = iter.ch;
var start = toTagStart(iter);
if (!start) return;
if (start[1]) { // closing tag
stack.push(start[2]);
} else { // opening tag
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
stack.length = i;
break;
}
if (i < 0 && (!tag || tag == start[2])) return {
tag: start[2],
from: Pos(iter.line, iter.ch),
to: Pos(endLine, endCh)
};
}
}
}
CodeMirror.registerHelper("fold", "xml", function(cm, start) {
var iter = new Iter(cm, start.line, 0);
for (;;) {
var openTag = toNextTag(iter), end;
if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
if (!openTag[1] && end != "selfClose") {
var startPos = Pos(iter.line, iter.ch);
var endPos = findMatchingClose(iter, openTag[2]);
return endPos && {from: startPos, to: endPos.from};
}
}
});
CodeMirror.findMatchingTag = function(cm, pos, range) {
var iter = new Iter(cm, pos.line, pos.ch, range);
if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
var start = end && toTagStart(iter);
if (!end || !start || cmp(iter, pos) > 0) return;
var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
if (end == "selfClose") return {open: here, close: null, at: "open"};
if (start[1]) { // closing tag
return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
} else { // opening tag
iter = new Iter(cm, to.line, to.ch, range);
return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};
}
};
CodeMirror.findEnclosingTag = function(cm, pos, range, tag) {
var iter = new Iter(cm, pos.line, pos.ch, range);
for (;;) {
var open = findMatchingOpen(iter, tag);
if (!open) break;
var forward = new Iter(cm, pos.line, pos.ch, range);
var close = findMatchingClose(forward, open.tag);
if (close) return {open: open, close: close};
}
};
// Used by addon/edit/closetag.js
CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
return findMatchingClose(iter, name);
};
});

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,49 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// Defines jumpToLine command. Uses dialog.js if present.
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../dialog/dialog"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../dialog/dialog"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
function dialog(cm, text, shortText, deflt, f) {
if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
else f(prompt(shortText, deflt));
}
var jumpDialog =
'Jump to line: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use line:column or scroll% syntax)</span>';
function interpretLine(cm, string) {
var num = Number(string)
if (/^[-+]/.test(string)) return cm.getCursor().line + num
else return num - 1
}
CodeMirror.commands.jumpToLine = function(cm) {
var cur = cm.getCursor();
dialog(cm, jumpDialog, "Jump to line:", (cur.line + 1) + ":" + cur.ch, function(posStr) {
if (!posStr) return;
var match;
if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) {
cm.setCursor(interpretLine(cm, match[1]), Number(match[2]))
} else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) {
var line = Math.round(cm.lineCount() * Number(match[1]) / 100);
if (/^[-+]/.test(match[1])) line = cur.line + line + 1;
cm.setCursor(line - 1, cur.ch);
} else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) {
cm.setCursor(interpretLine(cm, match[1]), cur.ch);
}
});
};
CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine";
});

View File

@@ -0,0 +1,165 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// Highlighting text that matches the selection
//
// Defines an option highlightSelectionMatches, which, when enabled,
// will style strings that match the selection throughout the
// document.
//
// The option can be set to true to simply enable it, or to a
// {minChars, style, wordsOnly, showToken, delay} object to explicitly
// configure it. minChars is the minimum amount of characters that should be
// selected for the behavior to occur, and style is the token style to
// apply to the matches. This will be prefixed by "cm-" to create an
// actual CSS class name. If wordsOnly is enabled, the matches will be
// highlighted only if the selected text is a word. showToken, when enabled,
// will cause the current token to be highlighted when nothing is selected.
// delay is used to specify how much time to wait, in milliseconds, before
// highlighting the matches. If annotateScrollbar is enabled, the occurences
// will be highlighted on the scrollbar via the matchesonscrollbar addon.
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./matchesonscrollbar"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./matchesonscrollbar"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var defaults = {
style: "matchhighlight",
minChars: 2,
delay: 100,
wordsOnly: false,
annotateScrollbar: false,
showToken: false,
trim: true
}
function State(options) {
this.options = {}
for (var name in defaults)
this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name]
this.overlay = this.timeout = null;
this.matchesonscroll = null;
this.active = false;
}
CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) {
removeOverlay(cm);
clearTimeout(cm.state.matchHighlighter.timeout);
cm.state.matchHighlighter = null;
cm.off("cursorActivity", cursorActivity);
cm.off("focus", onFocus)
}
if (val) {
var state = cm.state.matchHighlighter = new State(val);
if (cm.hasFocus()) {
state.active = true
highlightMatches(cm)
} else {
cm.on("focus", onFocus)
}
cm.on("cursorActivity", cursorActivity);
}
});
function cursorActivity(cm) {
var state = cm.state.matchHighlighter;
if (state.active || cm.hasFocus()) scheduleHighlight(cm, state)
}
function onFocus(cm) {
var state = cm.state.matchHighlighter
if (!state.active) {
state.active = true
scheduleHighlight(cm, state)
}
}
function scheduleHighlight(cm, state) {
clearTimeout(state.timeout);
state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay);
}
function addOverlay(cm, query, hasBoundary, style) {
var state = cm.state.matchHighlighter;
cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query;
state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false,
{className: "CodeMirror-selection-highlight-scrollbar"});
}
}
function removeOverlay(cm) {
var state = cm.state.matchHighlighter;
if (state.overlay) {
cm.removeOverlay(state.overlay);
state.overlay = null;
if (state.matchesonscroll) {
state.matchesonscroll.clear();
state.matchesonscroll = null;
}
}
}
function highlightMatches(cm) {
cm.operation(function() {
var state = cm.state.matchHighlighter;
removeOverlay(cm);
if (!cm.somethingSelected() && state.options.showToken) {
var re = state.options.showToken === true ? /[\w$]/ : state.options.showToken;
var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start;
while (start && re.test(line.charAt(start - 1))) --start;
while (end < line.length && re.test(line.charAt(end))) ++end;
if (start < end)
addOverlay(cm, line.slice(start, end), re, state.options.style);
return;
}
var from = cm.getCursor("from"), to = cm.getCursor("to");
if (from.line != to.line) return;
if (state.options.wordsOnly && !isWord(cm, from, to)) return;
var selection = cm.getRange(from, to)
if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "")
if (selection.length >= state.options.minChars)
addOverlay(cm, selection, false, state.options.style);
});
}
function isWord(cm, from, to) {
var str = cm.getRange(from, to);
if (str.match(/^\w+$/) !== null) {
if (from.ch > 0) {
var pos = {line: from.line, ch: from.ch - 1};
var chr = cm.getRange(pos, from);
if (chr.match(/\W/) === null) return false;
}
if (to.ch < cm.getLine(from.line).length) {
var pos = {line: to.line, ch: to.ch + 1};
var chr = cm.getRange(to, pos);
if (chr.match(/\W/) === null) return false;
}
return true;
} else return false;
}
function boundariesAround(stream, re) {
return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) &&
(stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos)));
}
function makeOverlay(query, hasBoundary, style) {
return {token: function(stream) {
if (stream.match(query) &&
(!hasBoundary || boundariesAround(stream, hasBoundary)))
return style;
stream.next();
stream.skipTo(query.charAt(0)) || stream.skipToEnd();
}};
}
});

View File

@@ -0,0 +1,8 @@
.CodeMirror-search-match {
background: gold;
border-top: 1px solid orange;
border-bottom: 1px solid orange;
-moz-box-sizing: border-box;
box-sizing: border-box;
opacity: .5;
}

View File

@@ -0,0 +1,97 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) {
if (typeof options == "string") options = {className: options};
if (!options) options = {};
return new SearchAnnotation(this, query, caseFold, options);
});
function SearchAnnotation(cm, query, caseFold, options) {
this.cm = cm;
this.options = options;
var annotateOptions = {listenForChanges: false};
for (var prop in options) annotateOptions[prop] = options[prop];
if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match";
this.annotation = cm.annotateScrollbar(annotateOptions);
this.query = query;
this.caseFold = caseFold;
this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1};
this.matches = [];
this.update = null;
this.findMatches();
this.annotation.update(this.matches);
var self = this;
cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); });
}
var MAX_MATCHES = 1000;
SearchAnnotation.prototype.findMatches = function() {
if (!this.gap) return;
for (var i = 0; i < this.matches.length; i++) {
var match = this.matches[i];
if (match.from.line >= this.gap.to) break;
if (match.to.line >= this.gap.from) this.matches.splice(i--, 1);
}
var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), this.caseFold);
var maxMatches = this.options && this.options.maxMatches || MAX_MATCHES;
while (cursor.findNext()) {
var match = {from: cursor.from(), to: cursor.to()};
if (match.from.line >= this.gap.to) break;
this.matches.splice(i++, 0, match);
if (this.matches.length > maxMatches) break;
}
this.gap = null;
};
function offsetLine(line, changeStart, sizeChange) {
if (line <= changeStart) return line;
return Math.max(changeStart, line + sizeChange);
}
SearchAnnotation.prototype.onChange = function(change) {
var startLine = change.from.line;
var endLine = CodeMirror.changeEnd(change).line;
var sizeChange = endLine - change.to.line;
if (this.gap) {
this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line);
this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line);
} else {
this.gap = {from: change.from.line, to: endLine + 1};
}
if (sizeChange) for (var i = 0; i < this.matches.length; i++) {
var match = this.matches[i];
var newFrom = offsetLine(match.from.line, startLine, sizeChange);
if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch);
var newTo = offsetLine(match.to.line, startLine, sizeChange);
if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch);
}
clearTimeout(this.update);
var self = this;
this.update = setTimeout(function() { self.updateAfterChange(); }, 250);
};
SearchAnnotation.prototype.updateAfterChange = function() {
this.findMatches();
this.annotation.update(this.matches);
};
SearchAnnotation.prototype.clear = function() {
this.cm.off("change", this.changeHandler);
this.annotation.clear();
};
});

View File

@@ -0,0 +1,252 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// Define search commands. Depends on dialog.js or another
// implementation of the openDialog method.
// Replace works a little oddly -- it will do the replace on the next
// Ctrl-G (or whatever is bound to findNext) press. You prevent a
// replace by making sure the match is no longer selected when hitting
// Ctrl-G.
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
function searchOverlay(query, caseInsensitive) {
if (typeof query == "string")
query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
else if (!query.global)
query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");
return {token: function(stream) {
query.lastIndex = stream.pos;
var match = query.exec(stream.string);
if (match && match.index == stream.pos) {
stream.pos += match[0].length || 1;
return "searching";
} else if (match) {
stream.pos = match.index;
} else {
stream.skipToEnd();
}
}};
}
function SearchState() {
this.posFrom = this.posTo = this.lastQuery = this.query = null;
this.overlay = null;
}
function getSearchState(cm) {
return cm.state.search || (cm.state.search = new SearchState());
}
function queryCaseInsensitive(query) {
return typeof query == "string" && query == query.toLowerCase();
}
function getSearchCursor(cm, query, pos) {
// Heuristic: if the query string is all lowercase, do a case insensitive search.
return cm.getSearchCursor(query, pos, {caseFold: queryCaseInsensitive(query), multiline: true});
}
function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
cm.openDialog(text, onEnter, {
value: deflt,
selectValueOnOpen: true,
closeOnEnter: false,
onClose: function() { clearSearch(cm); },
onKeyDown: onKeyDown
});
}
function dialog(cm, text, shortText, deflt, f) {
if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
else f(prompt(shortText, deflt));
}
function confirmDialog(cm, text, shortText, fs) {
if (cm.openConfirm) cm.openConfirm(text, fs);
else if (confirm(shortText)) fs[0]();
}
function parseString(string) {
return string.replace(/\\(.)/g, function(_, ch) {
if (ch == "n") return "\n"
if (ch == "r") return "\r"
return ch
})
}
function parseQuery(query) {
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
if (isRE) {
try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
catch(e) {} // Not a regular expression after all, do a string search
} else {
query = parseString(query)
}
if (typeof query == "string" ? query == "" : query.test(""))
query = /x^/;
return query;
}
var queryDialog =
'<span class="CodeMirror-search-label">Search:</span> <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
function startSearch(cm, state, query) {
state.queryText = query;
state.query = parseQuery(query);
cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
cm.addOverlay(state.overlay);
if (cm.showMatchesOnScrollbar) {
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
}
}
function doSearch(cm, rev, persistent, immediate) {
var state = getSearchState(cm);
if (state.query) return findNext(cm, rev);
var q = cm.getSelection() || state.lastQuery;
if (q instanceof RegExp && q.source == "x^") q = null
if (persistent && cm.openDialog) {
var hiding = null
var searchNext = function(query, event) {
CodeMirror.e_stop(event);
if (!query) return;
if (query != state.queryText) {
startSearch(cm, state, query);
state.posFrom = state.posTo = cm.getCursor();
}
if (hiding) hiding.style.opacity = 1
findNext(cm, event.shiftKey, function(_, to) {
var dialog
if (to.line < 3 && document.querySelector &&
(dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
(hiding = dialog).style.opacity = .4
})
};
persistentDialog(cm, queryDialog, q, searchNext, function(event, query) {
var keyName = CodeMirror.keyName(event)
var extra = cm.getOption('extraKeys'), cmd = (extra && extra[keyName]) || CodeMirror.keyMap[cm.getOption("keyMap")][keyName]
if (cmd == "findNext" || cmd == "findPrev" ||
cmd == "findPersistentNext" || cmd == "findPersistentPrev") {
CodeMirror.e_stop(event);
startSearch(cm, getSearchState(cm), query);
cm.execCommand(cmd);
} else if (cmd == "find" || cmd == "findPersistent") {
CodeMirror.e_stop(event);
searchNext(query, event);
}
});
if (immediate && q) {
startSearch(cm, state, q);
findNext(cm, rev);
}
} else {
dialog(cm, queryDialog, "Search for:", q, function(query) {
if (query && !state.query) cm.operation(function() {
startSearch(cm, state, query);
state.posFrom = state.posTo = cm.getCursor();
findNext(cm, rev);
});
});
}
}
function findNext(cm, rev, callback) {cm.operation(function() {
var state = getSearchState(cm);
var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
if (!cursor.find(rev)) {
cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
if (!cursor.find(rev)) return;
}
cm.setSelection(cursor.from(), cursor.to());
cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
state.posFrom = cursor.from(); state.posTo = cursor.to();
if (callback) callback(cursor.from(), cursor.to())
});}
function clearSearch(cm) {cm.operation(function() {
var state = getSearchState(cm);
state.lastQuery = state.query;
if (!state.query) return;
state.query = state.queryText = null;
cm.removeOverlay(state.overlay);
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
});}
var replaceQueryDialog =
' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
var replacementQueryDialog = '<span class="CodeMirror-search-label">With:</span> <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
var doReplaceConfirm = '<span class="CodeMirror-search-label">Replace?</span> <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>';
function replaceAll(cm, query, text) {
cm.operation(function() {
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
if (typeof query != "string") {
var match = cm.getRange(cursor.from(), cursor.to()).match(query);
cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
} else cursor.replace(text);
}
});
}
function replace(cm, all) {
if (cm.getOption("readOnly")) return;
var query = cm.getSelection() || getSearchState(cm).lastQuery;
var dialogText = '<span class="CodeMirror-search-label">' + (all ? 'Replace all:' : 'Replace:') + '</span>';
dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
if (!query) return;
query = parseQuery(query);
dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
text = parseString(text)
if (all) {
replaceAll(cm, query, text)
} else {
clearSearch(cm);
var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
var advance = function() {
var start = cursor.from(), match;
if (!(match = cursor.findNext())) {
cursor = getSearchCursor(cm, query);
if (!(match = cursor.findNext()) ||
(start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
}
cm.setSelection(cursor.from(), cursor.to());
cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
confirmDialog(cm, doReplaceConfirm, "Replace?",
[function() {doReplace(match);}, advance,
function() {replaceAll(cm, query, text)}]);
};
var doReplace = function(match) {
cursor.replace(typeof query == "string" ? text :
text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
advance();
};
advance();
}
});
});
}
CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};
CodeMirror.commands.findNext = doSearch;
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
CodeMirror.commands.clearSearch = clearSearch;
CodeMirror.commands.replace = replace;
CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
});

View File

@@ -0,0 +1,289 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"))
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod)
else // Plain browser env
mod(CodeMirror)
})(function(CodeMirror) {
"use strict"
var Pos = CodeMirror.Pos
function regexpFlags(regexp) {
var flags = regexp.flags
return flags != null ? flags : (regexp.ignoreCase ? "i" : "")
+ (regexp.global ? "g" : "")
+ (regexp.multiline ? "m" : "")
}
function ensureGlobal(regexp) {
return regexp.global ? regexp : new RegExp(regexp.source, regexpFlags(regexp) + "g")
}
function maybeMultiline(regexp) {
return /\\s|\\n|\n|\\W|\\D|\[\^/.test(regexp.source)
}
function searchRegexpForward(doc, regexp, start) {
regexp = ensureGlobal(regexp)
for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) {
regexp.lastIndex = ch
var string = doc.getLine(line), match = regexp.exec(string)
if (match)
return {from: Pos(line, match.index),
to: Pos(line, match.index + match[0].length),
match: match}
}
}
function searchRegexpForwardMultiline(doc, regexp, start) {
if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start)
regexp = ensureGlobal(regexp)
var string, chunk = 1
for (var line = start.line, last = doc.lastLine(); line <= last;) {
// This grows the search buffer in exponentially-sized chunks
// between matches, so that nearby matches are fast and don't
// require concatenating the whole document (in case we're
// searching for something that has tons of matches), but at the
// same time, the amount of retries is limited.
for (var i = 0; i < chunk; i++) {
var curLine = doc.getLine(line++)
string = string == null ? curLine : string + "\n" + curLine
}
chunk = chunk * 2
regexp.lastIndex = start.ch
var match = regexp.exec(string)
if (match) {
var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n")
var startLine = start.line + before.length - 1, startCh = before[before.length - 1].length
return {from: Pos(startLine, startCh),
to: Pos(startLine + inside.length - 1,
inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length),
match: match}
}
}
}
function lastMatchIn(string, regexp) {
var cutOff = 0, match
for (;;) {
regexp.lastIndex = cutOff
var newMatch = regexp.exec(string)
if (!newMatch) return match
match = newMatch
cutOff = match.index + (match[0].length || 1)
if (cutOff == string.length) return match
}
}
function searchRegexpBackward(doc, regexp, start) {
regexp = ensureGlobal(regexp)
for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) {
var string = doc.getLine(line)
if (ch > -1) string = string.slice(0, ch)
var match = lastMatchIn(string, regexp)
if (match)
return {from: Pos(line, match.index),
to: Pos(line, match.index + match[0].length),
match: match}
}
}
function searchRegexpBackwardMultiline(doc, regexp, start) {
regexp = ensureGlobal(regexp)
var string, chunk = 1
for (var line = start.line, first = doc.firstLine(); line >= first;) {
for (var i = 0; i < chunk; i++) {
var curLine = doc.getLine(line--)
string = string == null ? curLine.slice(0, start.ch) : curLine + "\n" + string
}
chunk *= 2
var match = lastMatchIn(string, regexp)
if (match) {
var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n")
var startLine = line + before.length, startCh = before[before.length - 1].length
return {from: Pos(startLine, startCh),
to: Pos(startLine + inside.length - 1,
inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length),
match: match}
}
}
}
var doFold, noFold
if (String.prototype.normalize) {
doFold = function(str) { return str.normalize("NFD").toLowerCase() }
noFold = function(str) { return str.normalize("NFD") }
} else {
doFold = function(str) { return str.toLowerCase() }
noFold = function(str) { return str }
}
// Maps a position in a case-folded line back to a position in the original line
// (compensating for codepoints increasing in number during folding)
function adjustPos(orig, folded, pos, foldFunc) {
if (orig.length == folded.length) return pos
for (var min = 0, max = pos + Math.max(0, orig.length - folded.length);;) {
if (min == max) return min
var mid = (min + max) >> 1
var len = foldFunc(orig.slice(0, mid)).length
if (len == pos) return mid
else if (len > pos) max = mid
else min = mid + 1
}
}
function searchStringForward(doc, query, start, caseFold) {
// Empty string would match anything and never progress, so we
// define it to match nothing instead.
if (!query.length) return null
var fold = caseFold ? doFold : noFold
var lines = fold(query).split(/\r|\n\r?/)
search: for (var line = start.line, ch = start.ch, last = doc.lastLine() + 1 - lines.length; line <= last; line++, ch = 0) {
var orig = doc.getLine(line).slice(ch), string = fold(orig)
if (lines.length == 1) {
var found = string.indexOf(lines[0])
if (found == -1) continue search
var start = adjustPos(orig, string, found, fold) + ch
return {from: Pos(line, adjustPos(orig, string, found, fold) + ch),
to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold) + ch)}
} else {
var cutFrom = string.length - lines[0].length
if (string.slice(cutFrom) != lines[0]) continue search
for (var i = 1; i < lines.length - 1; i++)
if (fold(doc.getLine(line + i)) != lines[i]) continue search
var end = doc.getLine(line + lines.length - 1), endString = fold(end), lastLine = lines[lines.length - 1]
if (end.slice(0, lastLine.length) != lastLine) continue search
return {from: Pos(line, adjustPos(orig, string, cutFrom, fold) + ch),
to: Pos(line + lines.length - 1, adjustPos(end, endString, lastLine.length, fold))}
}
}
}
function searchStringBackward(doc, query, start, caseFold) {
if (!query.length) return null
var fold = caseFold ? doFold : noFold
var lines = fold(query).split(/\r|\n\r?/)
search: for (var line = start.line, ch = start.ch, first = doc.firstLine() - 1 + lines.length; line >= first; line--, ch = -1) {
var orig = doc.getLine(line)
if (ch > -1) orig = orig.slice(0, ch)
var string = fold(orig)
if (lines.length == 1) {
var found = string.lastIndexOf(lines[0])
if (found == -1) continue search
return {from: Pos(line, adjustPos(orig, string, found, fold)),
to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold))}
} else {
var lastLine = lines[lines.length - 1]
if (string.slice(0, lastLine.length) != lastLine) continue search
for (var i = 1, start = line - lines.length + 1; i < lines.length - 1; i++)
if (fold(doc.getLine(start + i)) != lines[i]) continue search
var top = doc.getLine(line + 1 - lines.length), topString = fold(top)
if (topString.slice(topString.length - lines[0].length) != lines[0]) continue search
return {from: Pos(line + 1 - lines.length, adjustPos(top, topString, top.length - lines[0].length, fold)),
to: Pos(line, adjustPos(orig, string, lastLine.length, fold))}
}
}
}
function SearchCursor(doc, query, pos, options) {
this.atOccurrence = false
this.doc = doc
pos = pos ? doc.clipPos(pos) : Pos(0, 0)
this.pos = {from: pos, to: pos}
var caseFold
if (typeof options == "object") {
caseFold = options.caseFold
} else { // Backwards compat for when caseFold was the 4th argument
caseFold = options
options = null
}
if (typeof query == "string") {
if (caseFold == null) caseFold = false
this.matches = function(reverse, pos) {
return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold)
}
} else {
query = ensureGlobal(query)
if (!options || options.multiline !== false)
this.matches = function(reverse, pos) {
return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos)
}
else
this.matches = function(reverse, pos) {
return (reverse ? searchRegexpBackward : searchRegexpForward)(doc, query, pos)
}
}
}
SearchCursor.prototype = {
findNext: function() {return this.find(false)},
findPrevious: function() {return this.find(true)},
find: function(reverse) {
var result = this.matches(reverse, this.doc.clipPos(reverse ? this.pos.from : this.pos.to))
// Implements weird auto-growing behavior on null-matches for
// backwards-compatiblity with the vim code (unfortunately)
while (result && CodeMirror.cmpPos(result.from, result.to) == 0) {
if (reverse) {
if (result.from.ch) result.from = Pos(result.from.line, result.from.ch - 1)
else if (result.from.line == this.doc.firstLine()) result = null
else result = this.matches(reverse, this.doc.clipPos(Pos(result.from.line - 1)))
} else {
if (result.to.ch < this.doc.getLine(result.to.line).length) result.to = Pos(result.to.line, result.to.ch + 1)
else if (result.to.line == this.doc.lastLine()) result = null
else result = this.matches(reverse, Pos(result.to.line + 1, 0))
}
}
if (result) {
this.pos = result
this.atOccurrence = true
return this.pos.match || true
} else {
var end = Pos(reverse ? this.doc.firstLine() : this.doc.lastLine() + 1, 0)
this.pos = {from: end, to: end}
return this.atOccurrence = false
}
},
from: function() {if (this.atOccurrence) return this.pos.from},
to: function() {if (this.atOccurrence) return this.pos.to},
replace: function(newText, origin) {
if (!this.atOccurrence) return
var lines = CodeMirror.splitLines(newText)
this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin)
this.pos.to = Pos(this.pos.from.line + lines.length - 1,
lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0))
}
}
CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
return new SearchCursor(this.doc, query, pos, caseFold)
})
CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
return new SearchCursor(this, query, pos, caseFold)
})
CodeMirror.defineExtension("selectMatches", function(query, caseFold) {
var ranges = []
var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold)
while (cur.findNext()) {
if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break
ranges.push({anchor: cur.from(), head: cur.to()})
}
if (ranges.length)
this.setSelections(ranges, 0)
})
});

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,341 @@
/* BASICS */
.CodeMirror {
/* Set height, width, borders, and global font properties here */
font-family: monospace;
height: 300px;
color: black;
direction: ltr;
}
/* PADDING */
.CodeMirror-lines {
padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre {
padding: 0 4px; /* Horizontal padding of content */
}
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
background-color: white; /* The little square between H and V scrollbars */
}
/* GUTTER */
.CodeMirror-gutters {
border-right: 1px solid #ddd;
background-color: #f7f7f7;
white-space: nowrap;
}
.CodeMirror-linenumbers {}
.CodeMirror-linenumber {
padding: 0 3px 0 5px;
min-width: 20px;
text-align: right;
color: #999;
white-space: nowrap;
}
.CodeMirror-guttermarker { color: black; }
.CodeMirror-guttermarker-subtle { color: #999; }
/* CURSOR */
.CodeMirror-cursor {
border-left: 1px solid black;
border-right: none;
width: 0;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.cm-fat-cursor .CodeMirror-cursor {
width: auto;
border: 0 !important;
background: #7e7;
}
.cm-fat-cursor div.CodeMirror-cursors {
z-index: 1;
}
.cm-animate-fat-cursor {
width: auto;
border: 0;
-webkit-animation: blink 1.06s steps(1) infinite;
-moz-animation: blink 1.06s steps(1) infinite;
animation: blink 1.06s steps(1) infinite;
background-color: #7e7;
}
@-moz-keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
@-webkit-keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
@keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
/* Can style cursor different in overwrite (non-insert) mode */
.CodeMirror-overwrite .CodeMirror-cursor {}
.cm-tab { display: inline-block; text-decoration: inherit; }
.CodeMirror-rulers {
position: absolute;
left: 0; right: 0; top: -50px; bottom: -20px;
overflow: hidden;
}
.CodeMirror-ruler {
border-left: 1px solid #ccc;
top: 0; bottom: 0;
position: absolute;
}
/* DEFAULT THEME */
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-negative {color: #d44;}
.cm-positive {color: #292;}
.cm-header, .cm-strong {font-weight: bold;}
.cm-em {font-style: italic;}
.cm-link {text-decoration: underline;}
.cm-strikethrough {text-decoration: line-through;}
.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable,
.cm-s-default .cm-punctuation,
.cm-s-default .cm-property,
.cm-s-default .cm-operator {}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}
.cm-s-default .cm-error {color: #f00;}
.cm-invalidchar {color: #f00;}
.CodeMirror-composing { border-bottom: 2px solid; }
/* Default styles for common addons */
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
.CodeMirror-activeline-background {background: #e8f2ff;}
/* STOP */
/* The rest of this file contains styles related to the mechanics of
the editor. You probably shouldn't touch them. */
.CodeMirror {
position: relative;
overflow: hidden;
background: white;
}
.CodeMirror-scroll {
overflow: scroll !important; /* Things will break if this is overridden */
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
}
.CodeMirror-sizer {
position: relative;
border-right: 30px solid transparent;
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actual scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
position: absolute;
z-index: 6;
display: none;
}
.CodeMirror-vscrollbar {
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
}
.CodeMirror-hscrollbar {
bottom: 0; left: 0;
overflow-y: hidden;
overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
right: 0; bottom: 0;
}
.CodeMirror-gutter-filler {
left: 0; bottom: 0;
}
.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
min-height: 100%;
z-index: 3;
}
.CodeMirror-gutter {
white-space: normal;
height: 100%;
display: inline-block;
vertical-align: top;
margin-bottom: -30px;
}
.CodeMirror-gutter-wrapper {
position: absolute;
z-index: 4;
background: none !important;
border: none !important;
}
.CodeMirror-gutter-background {
position: absolute;
top: 0; bottom: 0;
z-index: 4;
}
.CodeMirror-gutter-elt {
position: absolute;
cursor: default;
z-index: 4;
}
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
.CodeMirror-lines {
cursor: text;
min-height: 1px; /* prevents collapsing before first draw */
}
.CodeMirror pre {
/* Reset some styles that the rest of the page might have set */
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
border-width: 0;
background: transparent;
font-family: inherit;
font-size: inherit;
margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
z-index: 2;
position: relative;
overflow: visible;
-webkit-tap-highlight-color: transparent;
-webkit-font-variant-ligatures: contextual;
font-variant-ligatures: contextual;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-linebackground {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
z-index: 0;
}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
overflow: auto;
}
.CodeMirror-widget {}
.CodeMirror-rtl pre { direction: rtl; }
.CodeMirror-code {
outline: none;
}
/* Force content-box sizing for the elements where we expect it */
.CodeMirror-scroll,
.CodeMirror-sizer,
.CodeMirror-gutter,
.CodeMirror-gutters,
.CodeMirror-linenumber {
-moz-box-sizing: content-box;
box-sizing: content-box;
}
.CodeMirror-measure {
position: absolute;
width: 100%;
height: 0;
overflow: hidden;
visibility: hidden;
}
.CodeMirror-cursor {
position: absolute;
pointer-events: none;
}
.CodeMirror-measure pre { position: static; }
div.CodeMirror-cursors {
visibility: hidden;
position: relative;
z-index: 3;
}
div.CodeMirror-dragcursors {
visibility: visible;
}
.CodeMirror-focused div.CodeMirror-cursors {
visibility: visible;
}
.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
.CodeMirror-crosshair { cursor: crosshair; }
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
.cm-searching {
background-color: #ffa;
background-color: rgba(255, 255, 0, .4);
}
/* Used to force a border model for a node */
.cm-force-border { padding-right: .1px; }
@media print {
/* Hide the cursor when printing */
.CodeMirror div.CodeMirror-cursors {
visibility: hidden;
}
}
/* See issue #2901 */
.cm-tab-wrap-hack:after { content: ''; }
/* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext { background: none; }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,831 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("css", function(config, parserConfig) {
var inline = parserConfig.inline
if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
var indentUnit = config.indentUnit,
tokenHooks = parserConfig.tokenHooks,
documentTypes = parserConfig.documentTypes || {},
mediaTypes = parserConfig.mediaTypes || {},
mediaFeatures = parserConfig.mediaFeatures || {},
mediaValueKeywords = parserConfig.mediaValueKeywords || {},
propertyKeywords = parserConfig.propertyKeywords || {},
nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
fontProperties = parserConfig.fontProperties || {},
counterDescriptors = parserConfig.counterDescriptors || {},
colorKeywords = parserConfig.colorKeywords || {},
valueKeywords = parserConfig.valueKeywords || {},
allowNested = parserConfig.allowNested,
lineComment = parserConfig.lineComment,
supportsAtComponent = parserConfig.supportsAtComponent === true;
var type, override;
function ret(style, tp) { type = tp; return style; }
// Tokenizers
function tokenBase(stream, state) {
var ch = stream.next();
if (tokenHooks[ch]) {
var result = tokenHooks[ch](stream, state);
if (result !== false) return result;
}
if (ch == "@") {
stream.eatWhile(/[\w\\\-]/);
return ret("def", stream.current());
} else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
return ret(null, "compare");
} else if (ch == "\"" || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
} else if (ch == "#") {
stream.eatWhile(/[\w\\\-]/);
return ret("atom", "hash");
} else if (ch == "!") {
stream.match(/^\s*\w*/);
return ret("keyword", "important");
} else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
} else if (ch === "-") {
if (/[\d.]/.test(stream.peek())) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
} else if (stream.match(/^-[\w\\\-]+/)) {
stream.eatWhile(/[\w\\\-]/);
if (stream.match(/^\s*:/, false))
return ret("variable-2", "variable-definition");
return ret("variable-2", "variable");
} else if (stream.match(/^\w+-/)) {
return ret("meta", "meta");
}
} else if (/[,+>*\/]/.test(ch)) {
return ret(null, "select-op");
} else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
return ret("qualifier", "qualifier");
} else if (/[:;{}\[\]\(\)]/.test(ch)) {
return ret(null, ch);
} else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) ||
(ch == "d" && stream.match("omain(")) ||
(ch == "r" && stream.match("egexp("))) {
stream.backUp(1);
state.tokenize = tokenParenthesized;
return ret("property", "word");
} else if (/[\w\\\-]/.test(ch)) {
stream.eatWhile(/[\w\\\-]/);
return ret("property", "word");
} else {
return ret(null, null);
}
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, ch;
while ((ch = stream.next()) != null) {
if (ch == quote && !escaped) {
if (quote == ")") stream.backUp(1);
break;
}
escaped = !escaped && ch == "\\";
}
if (ch == quote || !escaped && quote != ")") state.tokenize = null;
return ret("string", "string");
};
}
function tokenParenthesized(stream, state) {
stream.next(); // Must be '('
if (!stream.match(/\s*[\"\')]/, false))
state.tokenize = tokenString(")");
else
state.tokenize = null;
return ret(null, "(");
}
// Context management
function Context(type, indent, prev) {
this.type = type;
this.indent = indent;
this.prev = prev;
}
function pushContext(state, stream, type, indent) {
state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context);
return type;
}
function popContext(state) {
if (state.context.prev)
state.context = state.context.prev;
return state.context.type;
}
function pass(type, stream, state) {
return states[state.context.type](type, stream, state);
}
function popAndPass(type, stream, state, n) {
for (var i = n || 1; i > 0; i--)
state.context = state.context.prev;
return pass(type, stream, state);
}
// Parser
function wordAsValue(stream) {
var word = stream.current().toLowerCase();
if (valueKeywords.hasOwnProperty(word))
override = "atom";
else if (colorKeywords.hasOwnProperty(word))
override = "keyword";
else
override = "variable";
}
var states = {};
states.top = function(type, stream, state) {
if (type == "{") {
return pushContext(state, stream, "block");
} else if (type == "}" && state.context.prev) {
return popContext(state);
} else if (supportsAtComponent && /@component/.test(type)) {
return pushContext(state, stream, "atComponentBlock");
} else if (/^@(-moz-)?document$/.test(type)) {
return pushContext(state, stream, "documentTypes");
} else if (/^@(media|supports|(-moz-)?document|import)$/.test(type)) {
return pushContext(state, stream, "atBlock");
} else if (/^@(font-face|counter-style)/.test(type)) {
state.stateArg = type;
return "restricted_atBlock_before";
} else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
return "keyframes";
} else if (type && type.charAt(0) == "@") {
return pushContext(state, stream, "at");
} else if (type == "hash") {
override = "builtin";
} else if (type == "word") {
override = "tag";
} else if (type == "variable-definition") {
return "maybeprop";
} else if (type == "interpolation") {
return pushContext(state, stream, "interpolation");
} else if (type == ":") {
return "pseudo";
} else if (allowNested && type == "(") {
return pushContext(state, stream, "parens");
}
return state.context.type;
};
states.block = function(type, stream, state) {
if (type == "word") {
var word = stream.current().toLowerCase();
if (propertyKeywords.hasOwnProperty(word)) {
override = "property";
return "maybeprop";
} else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
override = "string-2";
return "maybeprop";
} else if (allowNested) {
override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag";
return "block";
} else {
override += " error";
return "maybeprop";
}
} else if (type == "meta") {
return "block";
} else if (!allowNested && (type == "hash" || type == "qualifier")) {
override = "error";
return "block";
} else {
return states.top(type, stream, state);
}
};
states.maybeprop = function(type, stream, state) {
if (type == ":") return pushContext(state, stream, "prop");
return pass(type, stream, state);
};
states.prop = function(type, stream, state) {
if (type == ";") return popContext(state);
if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
if (type == "}" || type == "{") return popAndPass(type, stream, state);
if (type == "(") return pushContext(state, stream, "parens");
if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) {
override += " error";
} else if (type == "word") {
wordAsValue(stream);
} else if (type == "interpolation") {
return pushContext(state, stream, "interpolation");
}
return "prop";
};
states.propBlock = function(type, _stream, state) {
if (type == "}") return popContext(state);
if (type == "word") { override = "property"; return "maybeprop"; }
return state.context.type;
};
states.parens = function(type, stream, state) {
if (type == "{" || type == "}") return popAndPass(type, stream, state);
if (type == ")") return popContext(state);
if (type == "(") return pushContext(state, stream, "parens");
if (type == "interpolation") return pushContext(state, stream, "interpolation");
if (type == "word") wordAsValue(stream);
return "parens";
};
states.pseudo = function(type, stream, state) {
if (type == "meta") return "pseudo";
if (type == "word") {
override = "variable-3";
return state.context.type;
}
return pass(type, stream, state);
};
states.documentTypes = function(type, stream, state) {
if (type == "word" && documentTypes.hasOwnProperty(stream.current())) {
override = "tag";
return state.context.type;
} else {
return states.atBlock(type, stream, state);
}
};
states.atBlock = function(type, stream, state) {
if (type == "(") return pushContext(state, stream, "atBlock_parens");
if (type == "}" || type == ";") return popAndPass(type, stream, state);
if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
if (type == "interpolation") return pushContext(state, stream, "interpolation");
if (type == "word") {
var word = stream.current().toLowerCase();
if (word == "only" || word == "not" || word == "and" || word == "or")
override = "keyword";
else if (mediaTypes.hasOwnProperty(word))
override = "attribute";
else if (mediaFeatures.hasOwnProperty(word))
override = "property";
else if (mediaValueKeywords.hasOwnProperty(word))
override = "keyword";
else if (propertyKeywords.hasOwnProperty(word))
override = "property";
else if (nonStandardPropertyKeywords.hasOwnProperty(word))
override = "string-2";
else if (valueKeywords.hasOwnProperty(word))
override = "atom";
else if (colorKeywords.hasOwnProperty(word))
override = "keyword";
else
override = "error";
}
return state.context.type;
};
states.atComponentBlock = function(type, stream, state) {
if (type == "}")
return popAndPass(type, stream, state);
if (type == "{")
return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false);
if (type == "word")
override = "error";
return state.context.type;
};
states.atBlock_parens = function(type, stream, state) {
if (type == ")") return popContext(state);
if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
return states.atBlock(type, stream, state);
};
states.restricted_atBlock_before = function(type, stream, state) {
if (type == "{")
return pushContext(state, stream, "restricted_atBlock");
if (type == "word" && state.stateArg == "@counter-style") {
override = "variable";
return "restricted_atBlock_before";
}
return pass(type, stream, state);
};
states.restricted_atBlock = function(type, stream, state) {
if (type == "}") {
state.stateArg = null;
return popContext(state);
}
if (type == "word") {
if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) ||
(state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase())))
override = "error";
else
override = "property";
return "maybeprop";
}
return "restricted_atBlock";
};
states.keyframes = function(type, stream, state) {
if (type == "word") { override = "variable"; return "keyframes"; }
if (type == "{") return pushContext(state, stream, "top");
return pass(type, stream, state);
};
states.at = function(type, stream, state) {
if (type == ";") return popContext(state);
if (type == "{" || type == "}") return popAndPass(type, stream, state);
if (type == "word") override = "tag";
else if (type == "hash") override = "builtin";
return "at";
};
states.interpolation = function(type, stream, state) {
if (type == "}") return popContext(state);
if (type == "{" || type == ";") return popAndPass(type, stream, state);
if (type == "word") override = "variable";
else if (type != "variable" && type != "(" && type != ")") override = "error";
return "interpolation";
};
return {
startState: function(base) {
return {tokenize: null,
state: inline ? "block" : "top",
stateArg: null,
context: new Context(inline ? "block" : "top", base || 0, null)};
},
token: function(stream, state) {
if (!state.tokenize && stream.eatSpace()) return null;
var style = (state.tokenize || tokenBase)(stream, state);
if (style && typeof style == "object") {
type = style[1];
style = style[0];
}
override = style;
if (type != "comment")
state.state = states[state.state](type, stream, state);
return override;
},
indent: function(state, textAfter) {
var cx = state.context, ch = textAfter && textAfter.charAt(0);
var indent = cx.indent;
if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev;
if (cx.prev) {
if (ch == "}" && (cx.type == "block" || cx.type == "top" ||
cx.type == "interpolation" || cx.type == "restricted_atBlock")) {
// Resume indentation from parent context.
cx = cx.prev;
indent = cx.indent;
} else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") ||
ch == "{" && (cx.type == "at" || cx.type == "atBlock")) {
// Dedent relative to current context.
indent = Math.max(0, cx.indent - indentUnit);
}
}
return indent;
},
electricChars: "}",
blockCommentStart: "/*",
blockCommentEnd: "*/",
lineComment: lineComment,
fold: "brace"
};
});
function keySet(array) {
var keys = {};
for (var i = 0; i < array.length; ++i) {
keys[array[i].toLowerCase()] = true;
}
return keys;
}
var documentTypes_ = [
"domain", "regexp", "url", "url-prefix"
], documentTypes = keySet(documentTypes_);
var mediaTypes_ = [
"all", "aural", "braille", "handheld", "print", "projection", "screen",
"tty", "tv", "embossed"
], mediaTypes = keySet(mediaTypes_);
var mediaFeatures_ = [
"width", "min-width", "max-width", "height", "min-height", "max-height",
"device-width", "min-device-width", "max-device-width", "device-height",
"min-device-height", "max-device-height", "aspect-ratio",
"min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
"min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
"max-color", "color-index", "min-color-index", "max-color-index",
"monochrome", "min-monochrome", "max-monochrome", "resolution",
"min-resolution", "max-resolution", "scan", "grid", "orientation",
"device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio",
"pointer", "any-pointer", "hover", "any-hover"
], mediaFeatures = keySet(mediaFeatures_);
var mediaValueKeywords_ = [
"landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover",
"interlace", "progressive"
], mediaValueKeywords = keySet(mediaValueKeywords_);
var propertyKeywords_ = [
"align-content", "align-items", "align-self", "alignment-adjust",
"alignment-baseline", "anchor-point", "animation", "animation-delay",
"animation-direction", "animation-duration", "animation-fill-mode",
"animation-iteration-count", "animation-name", "animation-play-state",
"animation-timing-function", "appearance", "azimuth", "backface-visibility",
"background", "background-attachment", "background-blend-mode", "background-clip",
"background-color", "background-image", "background-origin", "background-position",
"background-repeat", "background-size", "baseline-shift", "binding",
"bleed", "bookmark-label", "bookmark-level", "bookmark-state",
"bookmark-target", "border", "border-bottom", "border-bottom-color",
"border-bottom-left-radius", "border-bottom-right-radius",
"border-bottom-style", "border-bottom-width", "border-collapse",
"border-color", "border-image", "border-image-outset",
"border-image-repeat", "border-image-slice", "border-image-source",
"border-image-width", "border-left", "border-left-color",
"border-left-style", "border-left-width", "border-radius", "border-right",
"border-right-color", "border-right-style", "border-right-width",
"border-spacing", "border-style", "border-top", "border-top-color",
"border-top-left-radius", "border-top-right-radius", "border-top-style",
"border-top-width", "border-width", "bottom", "box-decoration-break",
"box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
"caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count",
"column-fill", "column-gap", "column-rule", "column-rule-color",
"column-rule-style", "column-rule-width", "column-span", "column-width",
"columns", "content", "counter-increment", "counter-reset", "crop", "cue",
"cue-after", "cue-before", "cursor", "direction", "display",
"dominant-baseline", "drop-initial-after-adjust",
"drop-initial-after-align", "drop-initial-before-adjust",
"drop-initial-before-align", "drop-initial-size", "drop-initial-value",
"elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
"flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
"float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
"font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
"font-stretch", "font-style", "font-synthesis", "font-variant",
"font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
"font-variant-ligatures", "font-variant-numeric", "font-variant-position",
"font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
"grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
"grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap",
"grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns",
"grid-template-rows", "hanging-punctuation", "height", "hyphens",
"icon", "image-orientation", "image-rendering", "image-resolution",
"inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing",
"line-break", "line-height", "line-stacking", "line-stacking-ruby",
"line-stacking-shift", "line-stacking-strategy", "list-style",
"list-style-image", "list-style-position", "list-style-type", "margin",
"margin-bottom", "margin-left", "margin-right", "margin-top",
"marks", "marquee-direction", "marquee-loop",
"marquee-play-count", "marquee-speed", "marquee-style", "max-height",
"max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
"nav-left", "nav-right", "nav-up", "object-fit", "object-position",
"opacity", "order", "orphans", "outline",
"outline-color", "outline-offset", "outline-style", "outline-width",
"overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
"padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
"page", "page-break-after", "page-break-before", "page-break-inside",
"page-policy", "pause", "pause-after", "pause-before", "perspective",
"perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position",
"presentation-level", "punctuation-trim", "quotes", "region-break-after",
"region-break-before", "region-break-inside", "region-fragment",
"rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
"right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
"ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
"shape-outside", "size", "speak", "speak-as", "speak-header",
"speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
"tab-size", "table-layout", "target", "target-name", "target-new",
"target-position", "text-align", "text-align-last", "text-decoration",
"text-decoration-color", "text-decoration-line", "text-decoration-skip",
"text-decoration-style", "text-emphasis", "text-emphasis-color",
"text-emphasis-position", "text-emphasis-style", "text-height",
"text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
"text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
"text-wrap", "top", "transform", "transform-origin", "transform-style",
"transition", "transition-delay", "transition-duration",
"transition-property", "transition-timing-function", "unicode-bidi",
"user-select", "vertical-align", "visibility", "voice-balance", "voice-duration",
"voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
"voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break",
"word-spacing", "word-wrap", "z-index",
// SVG-specific
"clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
"flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
"color-interpolation", "color-interpolation-filters",
"color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
"marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
"stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
"stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
"baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
"glyph-orientation-vertical", "text-anchor", "writing-mode"
], propertyKeywords = keySet(propertyKeywords_);
var nonStandardPropertyKeywords_ = [
"scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
"scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
"scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
"searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
"searchfield-results-decoration", "zoom"
], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
var fontProperties_ = [
"font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
"font-stretch", "font-weight", "font-style"
], fontProperties = keySet(fontProperties_);
var counterDescriptors_ = [
"additive-symbols", "fallback", "negative", "pad", "prefix", "range",
"speak-as", "suffix", "symbols", "system"
], counterDescriptors = keySet(counterDescriptors_);
var colorKeywords_ = [
"aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
"bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
"burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
"cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
"darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
"darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
"darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
"deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
"floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
"gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
"hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
"lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
"lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
"lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
"lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
"maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
"mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
"mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
"navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
"orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
"papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
"purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown",
"salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
"slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
"teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
"whitesmoke", "yellow", "yellowgreen"
], colorKeywords = keySet(colorKeywords_);
var valueKeywords_ = [
"above", "absolute", "activeborder", "additive", "activecaption", "afar",
"after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
"always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
"arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page",
"avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
"bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
"both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
"buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian",
"capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
"cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
"cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
"col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
"compact", "condensed", "contain", "content", "contents",
"content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
"cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
"decimal-leading-zero", "default", "default-button", "dense", "destination-atop",
"destination-in", "destination-out", "destination-over", "devanagari", "difference",
"disc", "discard", "disclosure-closed", "disclosure-open", "document",
"dot-dash", "dot-dot-dash",
"dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
"element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
"ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
"ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
"ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
"ethiopic-halehame-gez", "ethiopic-halehame-om-et",
"ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
"ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
"ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
"extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
"forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove",
"gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
"help", "hidden", "hide", "higher", "highlight", "highlighttext",
"hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore",
"inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
"infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
"inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert",
"italic", "japanese-formal", "japanese-informal", "justify", "kannada",
"katakana", "katakana-iroha", "keep-all", "khmer",
"korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal",
"landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten",
"line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem",
"local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
"lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
"lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d",
"media-controls-background", "media-current-time-display",
"media-fullscreen-button", "media-mute-button", "media-play-button",
"media-return-to-realtime-button", "media-rewind-button",
"media-seek-back-button", "media-seek-forward-button", "media-slider",
"media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
"media-volume-slider-container", "media-volume-sliderthumb", "medium",
"menu", "menulist", "menulist-button", "menulist-text",
"menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
"mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
"narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
"no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
"ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote",
"optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
"outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
"painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
"pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d",
"progress", "push-button", "radial-gradient", "radio", "read-only",
"read-write", "read-write-plaintext-only", "rectangle", "region",
"relative", "repeat", "repeating-linear-gradient",
"repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse",
"rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
"rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
"s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
"scroll", "scrollbar", "scroll-position", "se-resize", "searchfield",
"searchfield-cancel-button", "searchfield-decoration",
"searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end",
"semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
"simp-chinese-formal", "simp-chinese-informal", "single",
"skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal",
"slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
"small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
"source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square",
"square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
"subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table",
"table-caption", "table-cell", "table-column", "table-column-group",
"table-footer-group", "table-header-group", "table-row", "table-row-group",
"tamil",
"telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
"thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
"threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
"tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
"trad-chinese-formal", "trad-chinese-informal", "transform",
"translate", "translate3d", "translateX", "translateY", "translateZ",
"transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up",
"upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
"upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
"var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
"visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
"window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor",
"xx-large", "xx-small"
], valueKeywords = keySet(valueKeywords_);
var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_)
.concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_)
.concat(valueKeywords_);
CodeMirror.registerHelper("hintWords", "css", allWords);
function tokenCComment(stream, state) {
var maybeEnd = false, ch;
while ((ch = stream.next()) != null) {
if (maybeEnd && ch == "/") {
state.tokenize = null;
break;
}
maybeEnd = (ch == "*");
}
return ["comment", "comment"];
}
CodeMirror.defineMIME("text/css", {
documentTypes: documentTypes,
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
mediaValueKeywords: mediaValueKeywords,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
fontProperties: fontProperties,
counterDescriptors: counterDescriptors,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
tokenHooks: {
"/": function(stream, state) {
if (!stream.eat("*")) return false;
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
}
},
name: "css"
});
CodeMirror.defineMIME("text/x-scss", {
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
mediaValueKeywords: mediaValueKeywords,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
fontProperties: fontProperties,
allowNested: true,
lineComment: "//",
tokenHooks: {
"/": function(stream, state) {
if (stream.eat("/")) {
stream.skipToEnd();
return ["comment", "comment"];
} else if (stream.eat("*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
} else {
return ["operator", "operator"];
}
},
":": function(stream) {
if (stream.match(/\s*\{/, false))
return [null, null]
return false;
},
"$": function(stream) {
stream.match(/^[\w-]+/);
if (stream.match(/^\s*:/, false))
return ["variable-2", "variable-definition"];
return ["variable-2", "variable"];
},
"#": function(stream) {
if (!stream.eat("{")) return false;
return [null, "interpolation"];
}
},
name: "css",
helperType: "scss"
});
CodeMirror.defineMIME("text/x-less", {
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
mediaValueKeywords: mediaValueKeywords,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
fontProperties: fontProperties,
allowNested: true,
lineComment: "//",
tokenHooks: {
"/": function(stream, state) {
if (stream.eat("/")) {
stream.skipToEnd();
return ["comment", "comment"];
} else if (stream.eat("*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
} else {
return ["operator", "operator"];
}
},
"@": function(stream) {
if (stream.eat("{")) return [null, "interpolation"];
if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
stream.eatWhile(/[\w\\\-]/);
if (stream.match(/^\s*:/, false))
return ["variable-2", "variable-definition"];
return ["variable-2", "variable"];
},
"&": function() {
return ["atom", "atom"];
}
},
name: "css",
helperType: "less"
});
CodeMirror.defineMIME("text/x-gss", {
documentTypes: documentTypes,
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
fontProperties: fontProperties,
counterDescriptors: counterDescriptors,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
supportsAtComponent: true,
tokenHooks: {
"/": function(stream, state) {
if (!stream.eat("*")) return false;
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
}
},
name: "css",
helperType: "gss"
});
});

View File

@@ -0,0 +1,103 @@
<!doctype html>
<title>CodeMirror: Closure Stylesheets (GSS) mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<link rel="stylesheet" href="../../addon/hint/show-hint.css">
<script src="../../lib/codemirror.js"></script>
<script src="css.js"></script>
<script src="../../addon/hint/show-hint.js"></script>
<script src="../../addon/hint/css-hint.js"></script>
<style>.CodeMirror {background: #f8f8f8;}</style>
<div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">Closure Stylesheets (GSS)</a>
</ul>
</div>
<article>
<h2>Closure Stylesheets (GSS) mode</h2>
<form><textarea id="code" name="code">
/* Some example Closure Stylesheets */
@provide 'some.styles';
@require 'other.styles';
@component {
@def FONT_FAMILY "Times New Roman", Georgia, Serif;
@def FONT_SIZE_NORMAL 15px;
@def FONT_NORMAL normal FONT_SIZE_NORMAL FONT_FAMILY;
@def BG_COLOR rgb(235, 239, 249);
@def DIALOG_BORDER_COLOR rgb(107, 144, 218);
@def DIALOG_BG_COLOR BG_COLOR;
@def LEFT_HAND_NAV_WIDTH 180px;
@def LEFT_HAND_NAV_PADDING 3px;
@defmixin size(WIDTH, HEIGHT) {
width: WIDTH;
height: HEIGHT;
}
body {
background-color: BG_COLOR;
margin: 0;
padding: 3em 6em;
font: FONT_NORMAL;
color: #000;
}
#navigation a {
font-weight: bold;
text-decoration: none !important;
}
.dialog {
background-color: DIALOG_BG_COLOR;
border: 1px solid DIALOG_BORDER_COLOR;
}
.content {
position: absolute;
margin-left: add(LEFT_HAND_NAV_PADDING, /* padding left */
LEFT_HAND_NAV_WIDTH,
LEFT_HAND_NAV_PADDING); /* padding right */
}
.logo {
@mixin size(150px, 55px);
background-image: url('http://www.google.com/images/logo_sm.gif');
}
}
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
extraKeys: {"Ctrl-Space": "autocomplete"},
lineNumbers: true,
matchBrackets: "text/x-less",
mode: "text/x-gss"
});
</script>
<p>A mode for <a href="https://github.com/google/closure-stylesheets">Closure Stylesheets</a> (GSS).</p>
<p><strong>MIME type defined:</strong> <code>text/x-gss</code>.</p>
<p><strong>Parsing/Highlighting Tests:</strong> <a href="../../test/index.html#gss_*">normal</a>, <a href="../../test/index.html#verbose,gss_*">verbose</a>.</p>
</article>

View File

@@ -0,0 +1,17 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function() {
"use strict";
var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-gss");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "gss"); }
MT("atComponent",
"[def @component] {",
"[tag foo] {",
" [property color]: [keyword black];",
"}",
"}");
})();

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,152 @@
<!doctype html>
<title>CodeMirror: LESS mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../../addon/edit/matchbrackets.js"></script>
<script src="css.js"></script>
<style>.CodeMirror {border: 1px solid #ddd; line-height: 1.2;}</style>
<div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">LESS</a>
</ul>
</div>
<article>
<h2>LESS mode</h2>
<form><textarea id="code" name="code">@media screen and (device-aspect-ratio: 16/9) { … }
@media screen and (device-aspect-ratio: 1280/720) { … }
@media screen and (device-aspect-ratio: 2560/1440) { … }
html:lang(fr-be)
tr:nth-child(2n+1) /* represents every odd row of an HTML table */
img:nth-of-type(2n+1) { float: right; }
img:nth-of-type(2n) { float: left; }
body > h2:not(:first-of-type):not(:last-of-type)
html|*:not(:link):not(:visited)
*|*:not(:hover)
p::first-line { text-transform: uppercase }
@namespace foo url(http://www.example.com);
foo|h1 { color: blue } /* first rule */
span[hello="Ocean"][goodbye="Land"]
E[foo]{
padding:65px;
}
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button {
-webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5
}
button::-moz-focus-inner,
input::-moz-focus-inner { // Inner padding and border oddities in FF3/4
padding: 0;
border: 0;
}
.btn {
// reset here as of 2.0.3 due to Recess property order
border-color: #ccc;
border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);
}
fieldset span button, fieldset span input[type="file"] {
font-size:12px;
font-family:Arial, Helvetica, sans-serif;
}
.rounded-corners (@radius: 5px) {
border-radius: @radius;
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
}
@import url("something.css");
@light-blue: hsl(190, 50%, 65%);
#menu {
position: absolute;
width: 100%;
z-index: 3;
clear: both;
display: block;
background-color: @blue;
height: 42px;
border-top: 2px solid lighten(@alpha-blue, 20%);
border-bottom: 2px solid darken(@alpha-blue, 25%);
.box-shadow(0, 1px, 8px, 0.6);
-moz-box-shadow: 0 0 0 #000; // Because firefox sucks.
&.docked {
background-color: hsla(210, 60%, 40%, 0.4);
}
&:hover {
background-color: @blue;
}
#dropdown {
margin: 0 0 0 117px;
padding: 0;
padding-top: 5px;
display: none;
width: 190px;
border-top: 2px solid @medium;
color: @highlight;
border: 2px solid darken(@medium, 25%);
border-left-color: darken(@medium, 15%);
border-right-color: darken(@medium, 15%);
border-top-width: 0;
background-color: darken(@medium, 10%);
ul {
padding: 0px;
}
li {
font-size: 14px;
display: block;
text-align: left;
padding: 0;
border: 0;
a {
display: block;
padding: 0px 15px;
text-decoration: none;
color: white;
&:hover {
background-color: darken(@medium, 15%);
text-decoration: none;
}
}
}
.border-radius(5px, bottom);
.box-shadow(0, 6px, 8px, 0.5);
}
}
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers : true,
matchBrackets : true,
mode: "text/x-less"
});
</script>
<p>The LESS mode is a sub-mode of the <a href="index.html">CSS mode</a> (defined in <code>css.js</code>).</p>
<p><strong>Parsing/Highlighting Tests:</strong> <a href="../../test/index.html#less_*">normal</a>, <a href="../../test/index.html#verbose,less_*">verbose</a>.</p>
</article>

View File

@@ -0,0 +1,54 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function() {
"use strict";
var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-less");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "less"); }
MT("variable",
"[variable-2 @base]: [atom #f04615];",
"[qualifier .class] {",
" [property width]: [variable percentage]([number 0.5]); [comment // returns `50%`]",
" [property color]: [variable saturate]([variable-2 @base], [number 5%]);",
"}");
MT("amp",
"[qualifier .child], [qualifier .sibling] {",
" [qualifier .parent] [atom &] {",
" [property color]: [keyword black];",
" }",
" [atom &] + [atom &] {",
" [property color]: [keyword red];",
" }",
"}");
MT("mixin",
"[qualifier .mixin] ([variable dark]; [variable-2 @color]) {",
" [property color]: [atom darken]([variable-2 @color], [number 10%]);",
"}",
"[qualifier .mixin] ([variable light]; [variable-2 @color]) {",
" [property color]: [atom lighten]([variable-2 @color], [number 10%]);",
"}",
"[qualifier .mixin] ([variable-2 @_]; [variable-2 @color]) {",
" [property display]: [atom block];",
"}",
"[variable-2 @switch]: [variable light];",
"[qualifier .class] {",
" [qualifier .mixin]([variable-2 @switch]; [atom #888]);",
"}");
MT("nest",
"[qualifier .one] {",
" [def @media] ([property width]: [number 400px]) {",
" [property font-size]: [number 1.2em];",
" [def @media] [attribute print] [keyword and] [property color] {",
" [property color]: [keyword blue];",
" }",
" }",
"}");
MT("interpolation", ".@{[variable foo]} { [property font-weight]: [atom bold]; }");
})();

View File

@@ -0,0 +1,157 @@
<!doctype html>
<title>CodeMirror: SCSS mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="css.js"></script>
<style>.CodeMirror {background: #f8f8f8;}</style>
<div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">SCSS</a>
</ul>
</div>
<article>
<h2>SCSS mode</h2>
<form><textarea id="code" name="code">
/* Some example SCSS */
@import "compass/css3";
$variable: #333;
$blue: #3bbfce;
$margin: 16px;
.content-navigation {
#nested {
background-color: black;
}
border-color: $blue;
color:
darken($blue, 9%);
}
.border {
padding: $margin / 2;
margin: $margin / 2;
border-color: $blue;
}
@mixin table-base {
th {
text-align: center;
font-weight: bold;
}
td, th {padding: 2px}
}
table.hl {
margin: 2em 0;
td.ln {
text-align: right;
}
}
li {
font: {
family: serif;
weight: bold;
size: 1.2em;
}
}
@mixin left($dist) {
float: left;
margin-left: $dist;
}
#data {
@include left(10px);
@include table-base;
}
.source {
@include flow-into(target);
border: 10px solid green;
margin: 20px;
width: 200px; }
.new-container {
@include flow-from(target);
border: 10px solid red;
margin: 20px;
width: 200px; }
body {
margin: 0;
padding: 3em 6em;
font-family: tahoma, arial, sans-serif;
color: #000;
}
@mixin yellow() {
background: yellow;
}
.big {
font-size: 14px;
}
.nested {
@include border-radius(3px);
@extend .big;
p {
background: whitesmoke;
a {
color: red;
}
}
}
#navigation a {
font-weight: bold;
text-decoration: none !important;
}
h1 {
font-size: 2.5em;
}
h2 {
font-size: 1.7em;
}
h1:before, h2:before {
content: "::";
}
code {
font-family: courier, monospace;
font-size: 80%;
color: #418A8A;
}
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
matchBrackets: true,
mode: "text/x-scss"
});
</script>
<p>The SCSS mode is a sub-mode of the <a href="index.html">CSS mode</a> (defined in <code>css.js</code>).</p>
<p><strong>Parsing/Highlighting Tests:</strong> <a href="../../test/index.html#scss_*">normal</a>, <a href="../../test/index.html#verbose,scss_*">verbose</a>.</p>
</article>

View File

@@ -0,0 +1,110 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function() {
var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-scss");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); }
MT('url_with_quotation',
"[tag foo] { [property background]:[atom url]([string test.jpg]) }");
MT('url_with_double_quotes',
"[tag foo] { [property background]:[atom url]([string \"test.jpg\"]) }");
MT('url_with_single_quotes',
"[tag foo] { [property background]:[atom url]([string \'test.jpg\']) }");
MT('string',
"[def @import] [string \"compass/css3\"]");
MT('important_keyword',
"[tag foo] { [property background]:[atom url]([string \'test.jpg\']) [keyword !important] }");
MT('variable',
"[variable-2 $blue]:[atom #333]");
MT('variable_as_attribute',
"[tag foo] { [property color]:[variable-2 $blue] }");
MT('numbers',
"[tag foo] { [property padding]:[number 10px] [number 10] [number 10em] [number 8in] }");
MT('number_percentage',
"[tag foo] { [property width]:[number 80%] }");
MT('selector',
"[builtin #hello][qualifier .world]{}");
MT('singleline_comment',
"[comment // this is a comment]");
MT('multiline_comment',
"[comment /*foobar*/]");
MT('attribute_with_hyphen',
"[tag foo] { [property font-size]:[number 10px] }");
MT('string_after_attribute',
"[tag foo] { [property content]:[string \"::\"] }");
MT('directives',
"[def @include] [qualifier .mixin]");
MT('basic_structure',
"[tag p] { [property background]:[keyword red]; }");
MT('nested_structure',
"[tag p] { [tag a] { [property color]:[keyword red]; } }");
MT('mixin',
"[def @mixin] [tag table-base] {}");
MT('number_without_semicolon',
"[tag p] {[property width]:[number 12]}",
"[tag a] {[property color]:[keyword red];}");
MT('atom_in_nested_block',
"[tag p] { [tag a] { [property color]:[atom #000]; } }");
MT('interpolation_in_property',
"[tag foo] { #{[variable-2 $hello]}:[number 2]; }");
MT('interpolation_in_selector',
"[tag foo]#{[variable-2 $hello]} { [property color]:[atom #000]; }");
MT('interpolation_error',
"[tag foo]#{[variable foo]} { [property color]:[atom #000]; }");
MT("divide_operator",
"[tag foo] { [property width]:[number 4] [operator /] [number 2] }");
MT('nested_structure_with_id_selector',
"[tag p] { [builtin #hello] { [property color]:[keyword red]; } }");
MT('indent_mixin',
"[def @mixin] [tag container] (",
" [variable-2 $a]: [number 10],",
" [variable-2 $b]: [number 10])",
"{}");
MT('indent_nested',
"[tag foo] {",
" [tag bar] {",
" }",
"}");
MT('indent_parentheses',
"[tag foo] {",
" [property color]: [atom darken]([variable-2 $blue],",
" [number 9%]);",
"}");
MT('indent_vardef',
"[variable-2 $name]:",
" [string 'val'];",
"[tag tag] {",
" [tag inner] {",
" [property margin]: [number 3px];",
" }",
"}");
})();

View File

@@ -0,0 +1,206 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function() {
var mode = CodeMirror.getMode({indentUnit: 2}, "css");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
// Error, because "foobarhello" is neither a known type or property, but
// property was expected (after "and"), and it should be in parentheses.
MT("atMediaUnknownType",
"[def @media] [attribute screen] [keyword and] [error foobarhello] { }");
// Soft error, because "foobarhello" is not a known property or type.
MT("atMediaUnknownProperty",
"[def @media] [attribute screen] [keyword and] ([error foobarhello]) { }");
// Make sure nesting works with media queries
MT("atMediaMaxWidthNested",
"[def @media] [attribute screen] [keyword and] ([property max-width]: [number 25px]) { [tag foo] { } }");
MT("atMediaFeatureValueKeyword",
"[def @media] ([property orientation]: [keyword landscape]) { }");
MT("atMediaUnknownFeatureValueKeyword",
"[def @media] ([property orientation]: [error upsidedown]) { }");
MT("tagSelector",
"[tag foo] { }");
MT("classSelector",
"[qualifier .foo-bar_hello] { }");
MT("idSelector",
"[builtin #foo] { [error #foo] }");
MT("tagSelectorUnclosed",
"[tag foo] { [property margin]: [number 0] } [tag bar] { }");
MT("tagStringNoQuotes",
"[tag foo] { [property font-family]: [variable hello] [variable world]; }");
MT("tagStringDouble",
"[tag foo] { [property font-family]: [string \"hello world\"]; }");
MT("tagStringSingle",
"[tag foo] { [property font-family]: [string 'hello world']; }");
MT("tagColorKeyword",
"[tag foo] {",
" [property color]: [keyword black];",
" [property color]: [keyword navy];",
" [property color]: [keyword yellow];",
"}");
MT("tagColorHex3",
"[tag foo] { [property background]: [atom #fff]; }");
MT("tagColorHex4",
"[tag foo] { [property background]: [atom #ffff]; }");
MT("tagColorHex6",
"[tag foo] { [property background]: [atom #ffffff]; }");
MT("tagColorHex8",
"[tag foo] { [property background]: [atom #ffffffff]; }");
MT("tagColorHex5Invalid",
"[tag foo] { [property background]: [atom&error #fffff]; }");
MT("tagColorHexInvalid",
"[tag foo] { [property background]: [atom&error #ffg]; }");
MT("tagNegativeNumber",
"[tag foo] { [property margin]: [number -5px]; }");
MT("tagPositiveNumber",
"[tag foo] { [property padding]: [number 5px]; }");
MT("tagVendor",
"[tag foo] { [meta -foo-][property box-sizing]: [meta -foo-][atom border-box]; }");
MT("tagBogusProperty",
"[tag foo] { [property&error barhelloworld]: [number 0]; }");
MT("tagTwoProperties",
"[tag foo] { [property margin]: [number 0]; [property padding]: [number 0]; }");
MT("tagTwoPropertiesURL",
"[tag foo] { [property background]: [atom url]([string //example.com/foo.png]); [property padding]: [number 0]; }");
MT("indent_tagSelector",
"[tag strong], [tag em] {",
" [property background]: [atom rgba](",
" [number 255], [number 255], [number 0], [number .2]",
" );",
"}");
MT("indent_atMedia",
"[def @media] {",
" [tag foo] {",
" [property color]:",
" [keyword yellow];",
" }",
"}");
MT("indent_comma",
"[tag foo] {",
" [property font-family]: [variable verdana],",
" [atom sans-serif];",
"}");
MT("indent_parentheses",
"[tag foo]:[variable-3 before] {",
" [property background]: [atom url](",
"[string blahblah]",
"[string etc]",
"[string ]) [keyword !important];",
"}");
MT("font_face",
"[def @font-face] {",
" [property font-family]: [string 'myfont'];",
" [error nonsense]: [string 'abc'];",
" [property src]: [atom url]([string http://blah]),",
" [atom url]([string http://foo]);",
"}");
MT("empty_url",
"[def @import] [atom url]() [attribute screen];");
MT("parens",
"[qualifier .foo] {",
" [property background-image]: [variable fade]([atom #000], [number 20%]);",
" [property border-image]: [atom linear-gradient](",
" [atom to] [atom bottom],",
" [variable fade]([atom #000], [number 20%]) [number 0%],",
" [variable fade]([atom #000], [number 20%]) [number 100%]",
" );",
"}");
MT("css_variable",
":[variable-3 root] {",
" [variable-2 --main-color]: [atom #06c];",
"}",
"[tag h1][builtin #foo] {",
" [property color]: [atom var]([variable-2 --main-color]);",
"}");
MT("supports",
"[def @supports] ([keyword not] (([property text-align-last]: [atom justify]) [keyword or] ([meta -moz-][property text-align-last]: [atom justify])) {",
" [property text-align-last]: [atom justify];",
"}");
MT("document",
"[def @document] [tag url]([string http://blah]),",
" [tag url-prefix]([string https://]),",
" [tag domain]([string blah.com]),",
" [tag regexp]([string \".*blah.+\"]) {",
" [builtin #id] {",
" [property background-color]: [keyword white];",
" }",
" [tag foo] {",
" [property font-family]: [variable Verdana], [atom sans-serif];",
" }",
"}");
MT("document_url",
"[def @document] [tag url]([string http://blah]) { [qualifier .class] { } }");
MT("document_urlPrefix",
"[def @document] [tag url-prefix]([string https://]) { [builtin #id] { } }");
MT("document_domain",
"[def @document] [tag domain]([string blah.com]) { [tag foo] { } }");
MT("document_regexp",
"[def @document] [tag regexp]([string \".*blah.+\"]) { [builtin #id] { } }");
MT("counter-style",
"[def @counter-style] [variable binary] {",
" [property system]: [atom numeric];",
" [property symbols]: [number 0] [number 1];",
" [property suffix]: [string \".\"];",
" [property range]: [atom infinite];",
" [property speak-as]: [atom numeric];",
"}");
MT("counter-style-additive-symbols",
"[def @counter-style] [variable simple-roman] {",
" [property system]: [atom additive];",
" [property additive-symbols]: [number 10] [variable X], [number 5] [variable V], [number 1] [variable I];",
" [property range]: [number 1] [number 49];",
"}");
MT("counter-style-use",
"[tag ol][qualifier .roman] { [property list-style]: [variable simple-roman]; }");
MT("counter-style-symbols",
"[tag ol] { [property list-style]: [atom symbols]([atom cyclic] [string \"*\"] [string \"\\2020\"] [string \"\\2021\"] [string \"\\A7\"]); }");
MT("comment-does-not-disrupt",
"[def @font-face] [comment /* foo */] {",
" [property src]: [atom url]([string x]);",
" [property font-family]: [variable One];",
"}")
})();

View File

@@ -0,0 +1,152 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var defaultTags = {
script: [
["lang", /(javascript|babel)/i, "javascript"],
["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i, "javascript"],
["type", /./, "text/plain"],
[null, null, "javascript"]
],
style: [
["lang", /^css$/i, "css"],
["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"],
["type", /./, "text/plain"],
[null, null, "css"]
]
};
function maybeBackup(stream, pat, style) {
var cur = stream.current(), close = cur.search(pat);
if (close > -1) {
stream.backUp(cur.length - close);
} else if (cur.match(/<\/?$/)) {
stream.backUp(cur.length);
if (!stream.match(pat, false)) stream.match(cur);
}
return style;
}
var attrRegexpCache = {};
function getAttrRegexp(attr) {
var regexp = attrRegexpCache[attr];
if (regexp) return regexp;
return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*");
}
function getAttrValue(text, attr) {
var match = text.match(getAttrRegexp(attr))
return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : ""
}
function getTagRegexp(tagName, anchored) {
return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i");
}
function addTags(from, to) {
for (var tag in from) {
var dest = to[tag] || (to[tag] = []);
var source = from[tag];
for (var i = source.length - 1; i >= 0; i--)
dest.unshift(source[i])
}
}
function findMatchingMode(tagInfo, tagText) {
for (var i = 0; i < tagInfo.length; i++) {
var spec = tagInfo[i];
if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2];
}
}
CodeMirror.defineMode("htmlmixed", function (config, parserConfig) {
var htmlMode = CodeMirror.getMode(config, {
name: "xml",
htmlMode: true,
multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag
});
var tags = {};
var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes;
addTags(defaultTags, tags);
if (configTags) addTags(configTags, tags);
if (configScript) for (var i = configScript.length - 1; i >= 0; i--)
tags.script.unshift(["type", configScript[i].matches, configScript[i].mode])
function html(stream, state) {
var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName
if (tag && !/[<>\s\/]/.test(stream.current()) &&
(tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) &&
tags.hasOwnProperty(tagName)) {
state.inTag = tagName + " "
} else if (state.inTag && tag && />$/.test(stream.current())) {
var inTag = /^([\S]+) (.*)/.exec(state.inTag)
state.inTag = null
var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2])
var mode = CodeMirror.getMode(config, modeSpec)
var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false);
state.token = function (stream, state) {
if (stream.match(endTagA, false)) {
state.token = html;
state.localState = state.localMode = null;
return null;
}
return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState));
};
state.localMode = mode;
state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, ""));
} else if (state.inTag) {
state.inTag += stream.current()
if (stream.eol()) state.inTag += " "
}
return style;
};
return {
startState: function () {
var state = CodeMirror.startState(htmlMode);
return {token: html, inTag: null, localMode: null, localState: null, htmlState: state};
},
copyState: function (state) {
var local;
if (state.localState) {
local = CodeMirror.copyState(state.localMode, state.localState);
}
return {token: state.token, inTag: state.inTag,
localMode: state.localMode, localState: local,
htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
},
token: function (stream, state) {
return state.token(stream, state);
},
indent: function (state, textAfter, line) {
if (!state.localMode || /^\s*<\//.test(textAfter))
return htmlMode.indent(state.htmlState, textAfter);
else if (state.localMode.indent)
return state.localMode.indent(state.localState, textAfter, line);
else
return CodeMirror.Pass;
},
innerMode: function (state) {
return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
}
};
}, "xml", "javascript", "css");
CodeMirror.defineMIME("text/html", "htmlmixed");
});

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,847 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("javascript", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var statementIndent = parserConfig.statementIndent;
var jsonldMode = parserConfig.jsonld;
var jsonMode = parserConfig.json || jsonldMode;
var isTS = parserConfig.typescript;
var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
// Tokenizer
var keywords = function(){
function kw(type) {return {type: type, style: "keyword"};}
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
var jsKeywords = {
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
"return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "void": C, "throw": C, "debugger": C,
"var": kw("var"), "const": kw("var"), "let": kw("var"),
"function": kw("function"), "catch": kw("catch"),
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
"in": operator, "typeof": operator, "instanceof": operator,
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
"this": kw("this"), "class": kw("class"), "super": kw("atom"),
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
"await": C
};
// Extend the 'normal' keywords with the TypeScript language extensions
if (isTS) {
var type = {type: "variable", style: "type"};
var tsKeywords = {
// object-like things
"interface": kw("class"),
"implements": C,
"namespace": C,
"module": kw("module"),
"enum": kw("module"),
// scope modifiers
"public": kw("modifier"),
"private": kw("modifier"),
"protected": kw("modifier"),
"abstract": kw("modifier"),
"readonly": kw("modifier"),
// types
"string": type, "number": type, "boolean": type, "any": type
};
for (var attr in tsKeywords) {
jsKeywords[attr] = tsKeywords[attr];
}
}
return jsKeywords;
}();
var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
function readRegexp(stream) {
var escaped = false, next, inSet = false;
while ((next = stream.next()) != null) {
if (!escaped) {
if (next == "/" && !inSet) return;
if (next == "[") inSet = true;
else if (inSet && next == "]") inSet = false;
}
escaped = !escaped && next == "\\";
}
}
// Used as scratch variables to communicate multiple values without
// consing up tons of objects.
var type, content;
function ret(tp, style, cont) {
type = tp; content = cont;
return style;
}
function tokenBase(stream, state) {
var ch = stream.next();
if (ch == '"' || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
} else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
return ret("number", "number");
} else if (ch == "." && stream.match("..")) {
return ret("spread", "meta");
} else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
return ret(ch);
} else if (ch == "=" && stream.eat(">")) {
return ret("=>", "operator");
} else if (ch == "0" && stream.eat(/x/i)) {
stream.eatWhile(/[\da-f]/i);
return ret("number", "number");
} else if (ch == "0" && stream.eat(/o/i)) {
stream.eatWhile(/[0-7]/i);
return ret("number", "number");
} else if (ch == "0" && stream.eat(/b/i)) {
stream.eatWhile(/[01]/i);
return ret("number", "number");
} else if (/\d/.test(ch)) {
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
return ret("number", "number");
} else if (ch == "/") {
if (stream.eat("*")) {
state.tokenize = tokenComment;
return tokenComment(stream, state);
} else if (stream.eat("/")) {
stream.skipToEnd();
return ret("comment", "comment");
} else if (expressionAllowed(stream, state, 1)) {
readRegexp(stream);
stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
return ret("regexp", "string-2");
} else {
stream.eatWhile(isOperatorChar);
return ret("operator", "operator", stream.current());
}
} else if (ch == "`") {
state.tokenize = tokenQuasi;
return tokenQuasi(stream, state);
} else if (ch == "#") {
stream.skipToEnd();
return ret("error", "error");
} else if (isOperatorChar.test(ch)) {
if (ch != ">" || !state.lexical || state.lexical.type != ">")
stream.eatWhile(isOperatorChar);
return ret("operator", "operator", stream.current());
} else if (wordRE.test(ch)) {
stream.eatWhile(wordRE);
var word = stream.current()
if (state.lastType != ".") {
if (keywords.propertyIsEnumerable(word)) {
var kw = keywords[word]
return ret(kw.type, kw.style, word)
}
if (word == "async" && stream.match(/^\s*[\(\w]/, false))
return ret("async", "keyword", word)
}
return ret("variable", "variable", word)
}
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, next;
if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
state.tokenize = tokenBase;
return ret("jsonld-keyword", "meta");
}
while ((next = stream.next()) != null) {
if (next == quote && !escaped) break;
escaped = !escaped && next == "\\";
}
if (!escaped) state.tokenize = tokenBase;
return ret("string", "string");
};
}
function tokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
state.tokenize = tokenBase;
break;
}
maybeEnd = (ch == "*");
}
return ret("comment", "comment");
}
function tokenQuasi(stream, state) {
var escaped = false, next;
while ((next = stream.next()) != null) {
if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
state.tokenize = tokenBase;
break;
}
escaped = !escaped && next == "\\";
}
return ret("quasi", "string-2", stream.current());
}
var brackets = "([{}])";
// This is a crude lookahead trick to try and notice that we're
// parsing the argument patterns for a fat-arrow function before we
// actually hit the arrow token. It only works if the arrow is on
// the same line as the arguments and there's no strange noise
// (comments) in between. Fallback is to only notice when we hit the
// arrow, and not declare the arguments as locals for the arrow
// body.
function findFatArrow(stream, state) {
if (state.fatArrowAt) state.fatArrowAt = null;
var arrow = stream.string.indexOf("=>", stream.start);
if (arrow < 0) return;
if (isTS) { // Try to skip TypeScript return type declarations after the arguments
var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow))
if (m) arrow = m.index
}
var depth = 0, sawSomething = false;
for (var pos = arrow - 1; pos >= 0; --pos) {
var ch = stream.string.charAt(pos);
var bracket = brackets.indexOf(ch);
if (bracket >= 0 && bracket < 3) {
if (!depth) { ++pos; break; }
if (--depth == 0) { if (ch == "(") sawSomething = true; break; }
} else if (bracket >= 3 && bracket < 6) {
++depth;
} else if (wordRE.test(ch)) {
sawSomething = true;
} else if (/["'\/]/.test(ch)) {
return;
} else if (sawSomething && !depth) {
++pos;
break;
}
}
if (sawSomething && !depth) state.fatArrowAt = pos;
}
// Parser
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
function JSLexical(indented, column, type, align, prev, info) {
this.indented = indented;
this.column = column;
this.type = type;
this.prev = prev;
this.info = info;
if (align != null) this.align = align;
}
function inScope(state, varname) {
for (var v = state.localVars; v; v = v.next)
if (v.name == varname) return true;
for (var cx = state.context; cx; cx = cx.prev) {
for (var v = cx.vars; v; v = v.next)
if (v.name == varname) return true;
}
}
function parseJS(state, style, type, content, stream) {
var cc = state.cc;
// Communicate our context to the combinators.
// (Less wasteful than consing up a hundred closures on every call.)
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = true;
while(true) {
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
if (combinator(type, content)) {
while(cc.length && cc[cc.length - 1].lex)
cc.pop()();
if (cx.marked) return cx.marked;
if (type == "variable" && inScope(state, content)) return "variable-2";
return style;
}
}
}
// Combinator utils
var cx = {state: null, column: null, marked: null, cc: null};
function pass() {
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
}
function cont() {
pass.apply(null, arguments);
return true;
}
function register(varname) {
function inList(list) {
for (var v = list; v; v = v.next)
if (v.name == varname) return true;
return false;
}
var state = cx.state;
cx.marked = "def";
if (state.context) {
if (inList(state.localVars)) return;
state.localVars = {name: varname, next: state.localVars};
} else {
if (inList(state.globalVars)) return;
if (parserConfig.globalVars)
state.globalVars = {name: varname, next: state.globalVars};
}
}
// Combinators
var defaultVars = {name: "this", next: {name: "arguments"}};
function pushcontext() {
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
cx.state.localVars = defaultVars;
}
function popcontext() {
cx.state.localVars = cx.state.context.vars;
cx.state.context = cx.state.context.prev;
}
function pushlex(type, info) {
var result = function() {
var state = cx.state, indent = state.indented;
if (state.lexical.type == "stat") indent = state.lexical.indented;
else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
indent = outer.indented;
state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
};
result.lex = true;
return result;
}
function poplex() {
var state = cx.state;
if (state.lexical.prev) {
if (state.lexical.type == ")")
state.indented = state.lexical.indented;
state.lexical = state.lexical.prev;
}
}
poplex.lex = true;
function expect(wanted) {
function exp(type) {
if (type == wanted) return cont();
else if (wanted == ";") return pass();
else return cont(exp);
};
return exp;
}
function statement(type, value) {
if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
if (type == "{") return cont(pushlex("}"), block, poplex);
if (type == ";") return cont();
if (type == "if") {
if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
cx.state.cc.pop()();
return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse);
}
if (type == "function") return cont(functiondef);
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
if (type == "variable") {
if (isTS && value == "type") {
cx.marked = "keyword"
return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
} if (isTS && value == "declare") {
cx.marked = "keyword"
return cont(statement)
} else {
return cont(pushlex("stat"), maybelabel);
}
}
if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"),
block, poplex, poplex);
if (type == "case") return cont(expression, expect(":"));
if (type == "default") return cont(expect(":"));
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
statement, poplex, popcontext);
if (type == "class") return cont(pushlex("form"), className, poplex);
if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
if (type == "module") return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
if (type == "async") return cont(statement)
if (value == "@") return cont(expression, statement)
return pass(pushlex("stat"), expression, expect(";"), poplex);
}
function expression(type) {
return expressionInner(type, false);
}
function expressionNoComma(type) {
return expressionInner(type, true);
}
function parenExpr(type) {
if (type != "(") return pass()
return cont(pushlex(")"), expression, expect(")"), poplex)
}
function expressionInner(type, noComma) {
if (cx.state.fatArrowAt == cx.stream.start) {
var body = noComma ? arrowBodyNoComma : arrowBody;
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);
else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
}
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
if (type == "function") return cont(functiondef, maybeop);
if (type == "class") return cont(pushlex("form"), classExpression, poplex);
if (type == "keyword c" || type == "async") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
if (type == "{") return contCommasep(objprop, "}", null, maybeop);
if (type == "quasi") return pass(quasi, maybeop);
if (type == "new") return cont(maybeTarget(noComma));
return cont();
}
function maybeexpression(type) {
if (type.match(/[;\}\)\],]/)) return pass();
return pass(expression);
}
function maybeexpressionNoComma(type) {
if (type.match(/[;\}\)\],]/)) return pass();
return pass(expressionNoComma);
}
function maybeoperatorComma(type, value) {
if (type == ",") return cont(expression);
return maybeoperatorNoComma(type, value, false);
}
function maybeoperatorNoComma(type, value, noComma) {
var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
var expr = noComma == false ? expression : expressionNoComma;
if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
if (type == "operator") {
if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me);
if (value == "?") return cont(expression, expect(":"), expr);
return cont(expr);
}
if (type == "quasi") { return pass(quasi, me); }
if (type == ";") return;
if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
if (type == ".") return cont(property, me);
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
if (type == "regexp") {
cx.state.lastType = cx.marked = "operator"
cx.stream.backUp(cx.stream.pos - cx.stream.start - 1)
return cont(expr)
}
}
function quasi(type, value) {
if (type != "quasi") return pass();
if (value.slice(value.length - 2) != "${") return cont(quasi);
return cont(expression, continueQuasi);
}
function continueQuasi(type) {
if (type == "}") {
cx.marked = "string-2";
cx.state.tokenize = tokenQuasi;
return cont(quasi);
}
}
function arrowBody(type) {
findFatArrow(cx.stream, cx.state);
return pass(type == "{" ? statement : expression);
}
function arrowBodyNoComma(type) {
findFatArrow(cx.stream, cx.state);
return pass(type == "{" ? statement : expressionNoComma);
}
function maybeTarget(noComma) {
return function(type) {
if (type == ".") return cont(noComma ? targetNoComma : target);
else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma)
else return pass(noComma ? expressionNoComma : expression);
};
}
function target(_, value) {
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
}
function targetNoComma(_, value) {
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
}
function maybelabel(type) {
if (type == ":") return cont(poplex, statement);
return pass(maybeoperatorComma, expect(";"), poplex);
}
function property(type) {
if (type == "variable") {cx.marked = "property"; return cont();}
}
function objprop(type, value) {
if (type == "async") {
cx.marked = "property";
return cont(objprop);
} else if (type == "variable" || cx.style == "keyword") {
cx.marked = "property";
if (value == "get" || value == "set") return cont(getterSetter);
var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params
if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false)))
cx.state.fatArrowAt = cx.stream.pos + m[0].length
return cont(afterprop);
} else if (type == "number" || type == "string") {
cx.marked = jsonldMode ? "property" : (cx.style + " property");
return cont(afterprop);
} else if (type == "jsonld-keyword") {
return cont(afterprop);
} else if (type == "modifier") {
return cont(objprop)
} else if (type == "[") {
return cont(expression, expect("]"), afterprop);
} else if (type == "spread") {
return cont(expression, afterprop);
} else if (type == ":") {
return pass(afterprop)
}
}
function getterSetter(type) {
if (type != "variable") return pass(afterprop);
cx.marked = "property";
return cont(functiondef);
}
function afterprop(type) {
if (type == ":") return cont(expressionNoComma);
if (type == "(") return pass(functiondef);
}
function commasep(what, end, sep) {
function proceed(type, value) {
if (sep ? sep.indexOf(type) > -1 : type == ",") {
var lex = cx.state.lexical;
if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
return cont(function(type, value) {
if (type == end || value == end) return pass()
return pass(what)
}, proceed);
}
if (type == end || value == end) return cont();
return cont(expect(end));
}
return function(type, value) {
if (type == end || value == end) return cont();
return pass(what, proceed);
};
}
function contCommasep(what, end, info) {
for (var i = 3; i < arguments.length; i++)
cx.cc.push(arguments[i]);
return cont(pushlex(end, info), commasep(what, end), poplex);
}
function block(type) {
if (type == "}") return cont();
return pass(statement, block);
}
function maybetype(type, value) {
if (isTS) {
if (type == ":") return cont(typeexpr);
if (value == "?") return cont(maybetype);
}
}
function typeexpr(type, value) {
if (type == "variable") {
if (value == "keyof") {
cx.marked = "keyword"
return cont(typeexpr)
} else {
cx.marked = "type"
return cont(afterType)
}
}
if (type == "string" || type == "number" || type == "atom") return cont(afterType);
if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)
if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType)
if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
}
function maybeReturnType(type) {
if (type == "=>") return cont(typeexpr)
}
function typeprop(type, value) {
if (type == "variable" || cx.style == "keyword") {
cx.marked = "property"
return cont(typeprop)
} else if (value == "?") {
return cont(typeprop)
} else if (type == ":") {
return cont(typeexpr)
} else if (type == "[") {
return cont(expression, maybetype, expect("]"), typeprop)
}
}
function typearg(type) {
if (type == "variable") return cont(typearg)
else if (type == ":") return cont(typeexpr)
}
function afterType(type, value) {
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
if (value == "|" || type == ".") return cont(typeexpr)
if (type == "[") return cont(expect("]"), afterType)
if (value == "extends") return cont(typeexpr)
}
function maybeTypeArgs(_, value) {
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
}
function vardef() {
return pass(pattern, maybetype, maybeAssign, vardefCont);
}
function pattern(type, value) {
if (type == "modifier") return cont(pattern)
if (type == "variable") { register(value); return cont(); }
if (type == "spread") return cont(pattern);
if (type == "[") return contCommasep(pattern, "]");
if (type == "{") return contCommasep(proppattern, "}");
}
function proppattern(type, value) {
if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
register(value);
return cont(maybeAssign);
}
if (type == "variable") cx.marked = "property";
if (type == "spread") return cont(pattern);
if (type == "}") return pass();
return cont(expect(":"), pattern, maybeAssign);
}
function maybeAssign(_type, value) {
if (value == "=") return cont(expressionNoComma);
}
function vardefCont(type) {
if (type == ",") return cont(vardef);
}
function maybeelse(type, value) {
if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
}
function forspec(type) {
if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
}
function forspec1(type) {
if (type == "var") return cont(vardef, expect(";"), forspec2);
if (type == ";") return cont(forspec2);
if (type == "variable") return cont(formaybeinof);
return pass(expression, expect(";"), forspec2);
}
function formaybeinof(_type, value) {
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
return cont(maybeoperatorComma, forspec2);
}
function forspec2(type, value) {
if (type == ";") return cont(forspec3);
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
return pass(expression, expect(";"), forspec3);
}
function forspec3(type) {
if (type != ")") cont(expression);
}
function functiondef(type, value) {
if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
if (type == "variable") {register(value); return cont(functiondef);}
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
if (isTS && value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, functiondef)
}
function funarg(type, value) {
if (value == "@") cont(expression, funarg)
if (type == "spread" || type == "modifier") return cont(funarg);
return pass(pattern, maybetype, maybeAssign);
}
function classExpression(type, value) {
// Class expressions may have an optional name.
if (type == "variable") return className(type, value);
return classNameAfter(type, value);
}
function className(type, value) {
if (type == "variable") {register(value); return cont(classNameAfter);}
}
function classNameAfter(type, value) {
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, classNameAfter)
if (value == "extends" || value == "implements" || (isTS && type == ","))
return cont(isTS ? typeexpr : expression, classNameAfter);
if (type == "{") return cont(pushlex("}"), classBody, poplex);
}
function classBody(type, value) {
if (type == "modifier" || type == "async" ||
(type == "variable" &&
(value == "static" || value == "get" || value == "set") &&
cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) {
cx.marked = "keyword";
return cont(classBody);
}
if (type == "variable" || cx.style == "keyword") {
cx.marked = "property";
return cont(isTS ? classfield : functiondef, classBody);
}
if (type == "[")
return cont(expression, expect("]"), isTS ? classfield : functiondef, classBody)
if (value == "*") {
cx.marked = "keyword";
return cont(classBody);
}
if (type == ";") return cont(classBody);
if (type == "}") return cont();
if (value == "@") return cont(expression, classBody)
}
function classfield(type, value) {
if (value == "?") return cont(classfield)
if (type == ":") return cont(typeexpr, maybeAssign)
if (value == "=") return cont(expressionNoComma)
return pass(functiondef)
}
function afterExport(type, value) {
if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";"));
return pass(statement);
}
function exportField(type, value) {
if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
if (type == "variable") return pass(expressionNoComma, exportField);
}
function afterImport(type) {
if (type == "string") return cont();
return pass(importSpec, maybeMoreImports, maybeFrom);
}
function importSpec(type, value) {
if (type == "{") return contCommasep(importSpec, "}");
if (type == "variable") register(value);
if (value == "*") cx.marked = "keyword";
return cont(maybeAs);
}
function maybeMoreImports(type) {
if (type == ",") return cont(importSpec, maybeMoreImports)
}
function maybeAs(_type, value) {
if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
}
function maybeFrom(_type, value) {
if (value == "from") { cx.marked = "keyword"; return cont(expression); }
}
function arrayLiteral(type) {
if (type == "]") return cont();
return pass(commasep(expressionNoComma, "]"));
}
function isContinuedStatement(state, textAfter) {
return state.lastType == "operator" || state.lastType == "," ||
isOperatorChar.test(textAfter.charAt(0)) ||
/[,.]/.test(textAfter.charAt(0));
}
function expressionAllowed(stream, state, backUp) {
return state.tokenize == tokenBase &&
/^(?:operator|sof|keyword [bc]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
(state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
}
// Interface
return {
startState: function(basecolumn) {
var state = {
tokenize: tokenBase,
lastType: "sof",
cc: [],
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
localVars: parserConfig.localVars,
context: parserConfig.localVars && {vars: parserConfig.localVars},
indented: basecolumn || 0
};
if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
state.globalVars = parserConfig.globalVars;
return state;
},
token: function(stream, state) {
if (stream.sol()) {
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = false;
state.indented = stream.indentation();
findFatArrow(stream, state);
}
if (state.tokenize != tokenComment && stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
if (type == "comment") return style;
state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
return parseJS(state, style, type, content, stream);
},
indent: function(state, textAfter) {
if (state.tokenize == tokenComment) return CodeMirror.Pass;
if (state.tokenize != tokenBase) return 0;
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top
// Kludge to prevent 'maybelse' from blocking lexical scope pops
if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
var c = state.cc[i];
if (c == poplex) lexical = lexical.prev;
else if (c != maybeelse) break;
}
while ((lexical.type == "stat" || lexical.type == "form") &&
(firstChar == "}" || ((top = state.cc[state.cc.length - 1]) &&
(top == maybeoperatorComma || top == maybeoperatorNoComma) &&
!/^[,\.=+\-*:?[\(]/.test(textAfter))))
lexical = lexical.prev;
if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
lexical = lexical.prev;
var type = lexical.type, closing = firstChar == type;
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
else if (type == "form" && firstChar == "{") return lexical.indented;
else if (type == "form") return lexical.indented + indentUnit;
else if (type == "stat")
return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
else return lexical.indented + (closing ? 0 : indentUnit);
},
electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
blockCommentStart: jsonMode ? null : "/*",
blockCommentEnd: jsonMode ? null : "*/",
lineComment: jsonMode ? null : "//",
fold: "brace",
closeBrackets: "()[]{}''\"\"``",
helperType: jsonMode ? "json" : "javascript",
jsonldMode: jsonldMode,
jsonMode: jsonMode,
expressionAllowed: expressionAllowed,
skipExpression: function(state) {
var top = state.cc[state.cc.length - 1]
if (top == expression || top == expressionNoComma) state.cc.pop()
}
};
});
CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
CodeMirror.defineMIME("text/javascript", "javascript");
CodeMirror.defineMIME("text/ecmascript", "javascript");
CodeMirror.defineMIME("application/javascript", "javascript");
CodeMirror.defineMIME("application/x-javascript", "javascript");
CodeMirror.defineMIME("application/ecmascript", "javascript");
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
});

View File

@@ -0,0 +1,72 @@
<!doctype html>
<title>CodeMirror: JSON-LD mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../../addon/edit/matchbrackets.js"></script>
<script src="../../addon/comment/continuecomment.js"></script>
<script src="../../addon/comment/comment.js"></script>
<script src="javascript.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<div id="nav">
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"/></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">JSON-LD</a>
</ul>
</div>
<article>
<h2>JSON-LD mode</h2>
<div><textarea id="code" name="code">
{
"@context": {
"name": "http://schema.org/name",
"description": "http://schema.org/description",
"image": {
"@id": "http://schema.org/image",
"@type": "@id"
},
"geo": "http://schema.org/geo",
"latitude": {
"@id": "http://schema.org/latitude",
"@type": "xsd:float"
},
"longitude": {
"@id": "http://schema.org/longitude",
"@type": "xsd:float"
},
"xsd": "http://www.w3.org/2001/XMLSchema#"
},
"name": "The Empire State Building",
"description": "The Empire State Building is a 102-story landmark in New York City.",
"image": "http://www.civil.usherbrooke.ca/cours/gci215a/empire-state-building.jpg",
"geo": {
"latitude": "40.75",
"longitude": "73.98"
}
}
</textarea></div>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
matchBrackets: true,
autoCloseBrackets: true,
mode: "application/ld+json",
lineWrapping: true
});
</script>
<p>This is a specialization of the <a href="index.html">JavaScript mode</a>.</p>
</article>

View File

@@ -0,0 +1,404 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function() {
var mode = CodeMirror.getMode({indentUnit: 2}, "javascript");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
MT("locals",
"[keyword function] [def foo]([def a], [def b]) { [keyword var] [def c] [operator =] [number 10]; [keyword return] [variable-2 a] [operator +] [variable-2 c] [operator +] [variable d]; }");
MT("comma-and-binop",
"[keyword function](){ [keyword var] [def x] [operator =] [number 1] [operator +] [number 2], [def y]; }");
MT("destructuring",
"([keyword function]([def a], [[[def b], [def c] ]]) {",
" [keyword let] {[def d], [property foo]: [def c][operator =][number 10], [def x]} [operator =] [variable foo]([variable-2 a]);",
" [[[variable-2 c], [variable y] ]] [operator =] [variable-2 c];",
"})();");
MT("destructure_trailing_comma",
"[keyword let] {[def a], [def b],} [operator =] [variable foo];",
"[keyword let] [def c];"); // Parser still in good state?
MT("class_body",
"[keyword class] [def Foo] {",
" [property constructor]() {}",
" [property sayName]() {",
" [keyword return] [string-2 `foo${][variable foo][string-2 }oo`];",
" }",
"}");
MT("class",
"[keyword class] [def Point] [keyword extends] [variable SuperThing] {",
" [keyword get] [property prop]() { [keyword return] [number 24]; }",
" [property constructor]([def x], [def y]) {",
" [keyword super]([string 'something']);",
" [keyword this].[property x] [operator =] [variable-2 x];",
" }",
"}");
MT("anonymous_class_expression",
"[keyword const] [def Adder] [operator =] [keyword class] [keyword extends] [variable Arithmetic] {",
" [property add]([def a], [def b]) {}",
"};");
MT("named_class_expression",
"[keyword const] [def Subber] [operator =] [keyword class] [def Subtract] {",
" [property sub]([def a], [def b]) {}",
"};");
MT("class_async_method",
"[keyword class] [def Foo] {",
" [property sayName1]() {}",
" [keyword async] [property sayName2]() {}",
"}");
MT("import",
"[keyword function] [def foo]() {",
" [keyword import] [def $] [keyword from] [string 'jquery'];",
" [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];",
"}");
MT("import_trailing_comma",
"[keyword import] {[def foo], [def bar],} [keyword from] [string 'baz']")
MT("const",
"[keyword function] [def f]() {",
" [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];",
"}");
MT("for/of",
"[keyword for]([keyword let] [def of] [keyword of] [variable something]) {}");
MT("generator",
"[keyword function*] [def repeat]([def n]) {",
" [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])",
" [keyword yield] [variable-2 i];",
"}");
MT("quotedStringAddition",
"[keyword let] [def f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];");
MT("quotedFatArrow",
"[keyword let] [def f] [operator =] [variable a] [operator +] [string '=>'] [operator +] [variable c];");
MT("fatArrow",
"[variable array].[property filter]([def a] [operator =>] [variable-2 a] [operator +] [number 1]);",
"[variable a];", // No longer in scope
"[keyword let] [def f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];",
"[variable c];");
MT("spread",
"[keyword function] [def f]([def a], [meta ...][def b]) {",
" [variable something]([variable-2 a], [meta ...][variable-2 b]);",
"}");
MT("quasi",
"[variable re][string-2 `fofdlakj${][variable x] [operator +] ([variable re][string-2 `foo`]) [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]");
MT("quasi_no_function",
"[variable x] [operator =] [string-2 `fofdlakj${][variable x] [operator +] [string-2 `foo`] [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]");
MT("indent_statement",
"[keyword var] [def x] [operator =] [number 10]",
"[variable x] [operator +=] [variable y] [operator +]",
" [atom Infinity]",
"[keyword debugger];");
MT("indent_if",
"[keyword if] ([number 1])",
" [keyword break];",
"[keyword else] [keyword if] ([number 2])",
" [keyword continue];",
"[keyword else]",
" [number 10];",
"[keyword if] ([number 1]) {",
" [keyword break];",
"} [keyword else] [keyword if] ([number 2]) {",
" [keyword continue];",
"} [keyword else] {",
" [number 10];",
"}");
MT("indent_for",
"[keyword for] ([keyword var] [def i] [operator =] [number 0];",
" [variable i] [operator <] [number 100];",
" [variable i][operator ++])",
" [variable doSomething]([variable i]);",
"[keyword debugger];");
MT("indent_c_style",
"[keyword function] [def foo]()",
"{",
" [keyword debugger];",
"}");
MT("indent_else",
"[keyword for] (;;)",
" [keyword if] ([variable foo])",
" [keyword if] ([variable bar])",
" [number 1];",
" [keyword else]",
" [number 2];",
" [keyword else]",
" [number 3];");
MT("indent_funarg",
"[variable foo]([number 10000],",
" [keyword function]([def a]) {",
" [keyword debugger];",
"};");
MT("indent_below_if",
"[keyword for] (;;)",
" [keyword if] ([variable foo])",
" [number 1];",
"[number 2];");
MT("indent_semicolonless_if",
"[keyword function] [def foo]() {",
" [keyword if] ([variable x])",
" [variable foo]()",
"}")
MT("indent_semicolonless_if_with_statement",
"[keyword function] [def foo]() {",
" [keyword if] ([variable x])",
" [variable foo]()",
" [variable bar]()",
"}")
MT("multilinestring",
"[keyword var] [def x] [operator =] [string 'foo\\]",
"[string bar'];");
MT("scary_regexp",
"[string-2 /foo[[/]]bar/];");
MT("indent_strange_array",
"[keyword var] [def x] [operator =] [[",
" [number 1],,",
" [number 2],",
"]];",
"[number 10];");
MT("param_default",
"[keyword function] [def foo]([def x] [operator =] [string-2 `foo${][number 10][string-2 }bar`]) {",
" [keyword return] [variable-2 x];",
"}");
MT("new_target",
"[keyword function] [def F]([def target]) {",
" [keyword if] ([variable-2 target] [operator &&] [keyword new].[keyword target].[property name]) {",
" [keyword return] [keyword new]",
" .[keyword target];",
" }",
"}");
MT("async",
"[keyword async] [keyword function] [def foo]([def args]) { [keyword return] [atom true]; }");
MT("async_assignment",
"[keyword const] [def foo] [operator =] [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; };");
MT("async_object",
"[keyword let] [def obj] [operator =] { [property async]: [atom false] };");
// async be highlighet as keyword and foo as def, but it requires potentially expensive look-ahead. See #4173
MT("async_object_function",
"[keyword let] [def obj] [operator =] { [property async] [property foo]([def args]) { [keyword return] [atom true]; } };");
MT("async_object_properties",
"[keyword let] [def obj] [operator =] {",
" [property prop1]: [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; },",
" [property prop2]: [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; },",
" [property prop3]: [keyword async] [keyword function] [def prop3]([def args]) { [keyword return] [atom true]; },",
"};");
MT("async_arrow",
"[keyword const] [def foo] [operator =] [keyword async] ([def args]) [operator =>] { [keyword return] [atom true]; };");
MT("async_jquery",
"[variable $].[property ajax]({",
" [property url]: [variable url],",
" [property async]: [atom true],",
" [property method]: [string 'GET']",
"});");
MT("async_variable",
"[keyword const] [def async] [operator =] {[property a]: [number 1]};",
"[keyword const] [def foo] [operator =] [string-2 `bar ${][variable async].[property a][string-2 }`];")
MT("indent_switch",
"[keyword switch] ([variable x]) {",
" [keyword default]:",
" [keyword return] [number 2]",
"}")
MT("regexp_corner_case",
"[operator +]{} [operator /] [atom undefined];",
"[[[meta ...][string-2 /\\//] ]];",
"[keyword void] [string-2 /\\//];",
"[keyword do] [string-2 /\\//]; [keyword while] ([number 0]);",
"[keyword if] ([number 0]) {} [keyword else] [string-2 /\\//];",
"[string-2 `${][variable async][operator ++][string-2 }//`];",
"[string-2 `${]{} [operator /] [string-2 /\\//}`];")
var ts_mode = CodeMirror.getMode({indentUnit: 2}, "application/typescript")
function TS(name) {
test.mode(name, ts_mode, Array.prototype.slice.call(arguments, 1))
}
TS("typescript_extend_type",
"[keyword class] [def Foo] [keyword extends] [type Some][operator <][type Type][operator >] {}")
TS("typescript_arrow_type",
"[keyword let] [def x]: ([variable arg]: [type Type]) [operator =>] [type ReturnType]")
TS("typescript_class",
"[keyword class] [def Foo] {",
" [keyword public] [keyword static] [property main]() {}",
" [keyword private] [property _foo]: [type string];",
"}")
TS("typescript_literal_types",
"[keyword import] [keyword *] [keyword as] [def Sequelize] [keyword from] [string 'sequelize'];",
"[keyword interface] [def MyAttributes] {",
" [property truthy]: [string 'true'] [operator |] [number 1] [operator |] [atom true];",
" [property falsy]: [string 'false'] [operator |] [number 0] [operator |] [atom false];",
"}",
"[keyword interface] [def MyInstance] [keyword extends] [type Sequelize].[type Instance] [operator <] [type MyAttributes] [operator >] {",
" [property rawAttributes]: [type MyAttributes];",
" [property truthy]: [string 'true'] [operator |] [number 1] [operator |] [atom true];",
" [property falsy]: [string 'false'] [operator |] [number 0] [operator |] [atom false];",
"}")
TS("typescript_extend_operators",
"[keyword export] [keyword interface] [def UserModel] [keyword extends]",
" [type Sequelize].[type Model] [operator <] [type UserInstance], [type UserAttributes] [operator >] {",
" [property findById]: (",
" [variable userId]: [type number]",
" ) [operator =>] [type Promise] [operator <] [type Array] [operator <] { [property id], [property name] } [operator >>];",
" [property updateById]: (",
" [variable userId]: [type number],",
" [variable isActive]: [type boolean]",
" ) [operator =>] [type Promise] [operator <] [type AccountHolderNotificationPreferenceInstance] [operator >];",
" }")
TS("typescript_interface_with_const",
"[keyword const] [def hello]: {",
" [property prop1][operator ?]: [type string];",
" [property prop2][operator ?]: [type string];",
"} [operator =] {};")
TS("typescript_double_extend",
"[keyword export] [keyword interface] [def UserAttributes] {",
" [property id][operator ?]: [type number];",
" [property createdAt][operator ?]: [type Date];",
"}",
"[keyword export] [keyword interface] [def UserInstance] [keyword extends] [type Sequelize].[type Instance][operator <][type UserAttributes][operator >], [type UserAttributes] {",
" [property id]: [type number];",
" [property createdAt]: [type Date];",
"}");
TS("typescript_index_signature",
"[keyword interface] [def A] {",
" [[ [variable prop]: [type string] ]]: [type any];",
" [property prop1]: [type any];",
"}");
TS("typescript_generic_class",
"[keyword class] [def Foo][operator <][type T][operator >] {",
" [property bar]() {}",
" [property foo](): [type Foo] {}",
"}")
TS("typescript_type_when_keyword",
"[keyword export] [keyword type] [type AB] [operator =] [type A] [operator |] [type B];",
"[keyword type] [type Flags] [operator =] {",
" [property p1]: [type string];",
" [property p2]: [type boolean];",
"};")
TS("typescript_type_when_not_keyword",
"[keyword class] [def HasType] {",
" [property type]: [type string];",
" [property constructor]([def type]: [type string]) {",
" [keyword this].[property type] [operator =] [variable-2 type];",
" }",
" [property setType]({ [def type] }: { [property type]: [type string]; }) {",
" [keyword this].[property type] [operator =] [variable-2 type];",
" }",
"}")
TS("typescript_function_generics",
"[keyword function] [def a]() {}",
"[keyword function] [def b][operator <][type IA] [keyword extends] [type object], [type IB] [keyword extends] [type object][operator >]() {}",
"[keyword function] [def c]() {}")
TS("typescript_complex_return_type",
"[keyword function] [def A]() {",
" [keyword return] [keyword this].[property property];",
"}",
"[keyword function] [def B](): [type Promise][operator <]{ [[ [variable key]: [type string] ]]: [type any] } [operator |] [atom null][operator >] {",
" [keyword return] [keyword this].[property property];",
"}")
TS("typescript_complex_type_casting",
"[keyword const] [def giftpay] [operator =] [variable config].[property get]([string 'giftpay']) [keyword as] { [[ [variable platformUuid]: [type string] ]]: { [property version]: [type number]; [property apiCode]: [type string]; } };")
TS("typescript_keyof",
"[keyword function] [def x][operator <][type T] [keyword extends] [keyword keyof] [type X][operator >]([def a]: [type T]) {",
" [keyword return]")
TS("typescript_new_typeargs",
"[keyword let] [def x] [operator =] [keyword new] [variable Map][operator <][type string], [type Date][operator >]([string-2 `foo${][variable bar][string-2 }`])")
TS("modifiers",
"[keyword class] [def Foo] {",
" [keyword public] [keyword abstract] [property bar]() {}",
" [property constructor]([keyword readonly] [keyword private] [def x]) {}",
"}")
TS("arrow prop",
"({[property a]: [def p] [operator =>] [variable-2 p]})")
var jsonld_mode = CodeMirror.getMode(
{indentUnit: 2},
{name: "javascript", jsonld: true}
);
function LD(name) {
test.mode(name, jsonld_mode, Array.prototype.slice.call(arguments, 1));
}
LD("json_ld_keywords",
'{',
' [meta "@context"]: {',
' [meta "@base"]: [string "http://example.com"],',
' [meta "@vocab"]: [string "http://xmlns.com/foaf/0.1/"],',
' [property "likesFlavor"]: {',
' [meta "@container"]: [meta "@list"]',
' [meta "@reverse"]: [string "@beFavoriteOf"]',
' },',
' [property "nick"]: { [meta "@container"]: [meta "@set"] },',
' [property "nick"]: { [meta "@container"]: [meta "@index"] }',
' },',
' [meta "@graph"]: [[ {',
' [meta "@id"]: [string "http://dbpedia.org/resource/John_Lennon"],',
' [property "name"]: [string "John Lennon"],',
' [property "modified"]: {',
' [meta "@value"]: [string "2010-05-29T14:17:39+02:00"],',
' [meta "@type"]: [string "http://www.w3.org/2001/XMLSchema#dateTime"]',
' }',
' } ]]',
'}');
LD("json_ld_fake",
'{',
' [property "@fake"]: [string "@fake"],',
' [property "@contextual"]: [string "@identifier"],',
' [property "user@domain.com"]: [string "@graphical"],',
' [property "@ID"]: [string "@@ID"]',
'}');
})();

View File

@@ -0,0 +1,61 @@
<!doctype html>
<title>CodeMirror: TypeScript mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="javascript.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">TypeScript</a>
</ul>
</div>
<article>
<h2>TypeScript mode</h2>
<div><textarea id="code" name="code">
class Greeter {
greeting: string;
constructor (message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
var greeter = new Greeter("world");
var button = document.createElement('button')
button.innerText = "Say Hello"
button.onclick = function() {
alert(greeter.greet())
}
document.body.appendChild(button)
</textarea></div>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
matchBrackets: true,
mode: "text/typescript"
});
</script>
<p>This is a specialization of the <a href="index.html">JavaScript mode</a>.</p>
</article>

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,51 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function() {
var mode = CodeMirror.getMode({indentUnit: 2}, "xml"), mname = "xml";
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), mname); }
MT("matching",
"[tag&bracket <][tag top][tag&bracket >]",
" text",
" [tag&bracket <][tag inner][tag&bracket />]",
"[tag&bracket </][tag top][tag&bracket >]");
MT("nonmatching",
"[tag&bracket <][tag top][tag&bracket >]",
" [tag&bracket <][tag inner][tag&bracket />]",
" [tag&bracket </][tag&error tip][tag&bracket&error >]");
MT("doctype",
"[meta <!doctype foobar>]",
"[tag&bracket <][tag top][tag&bracket />]");
MT("cdata",
"[tag&bracket <][tag top][tag&bracket >]",
" [atom <![CDATA[foo]",
"[atom barbazguh]]]]>]",
"[tag&bracket </][tag top][tag&bracket >]");
// HTML tests
mode = CodeMirror.getMode({indentUnit: 2}, "text/html");
MT("selfclose",
"[tag&bracket <][tag html][tag&bracket >]",
" [tag&bracket <][tag link] [attribute rel]=[string stylesheet] [attribute href]=[string \"/foobar\"][tag&bracket >]",
"[tag&bracket </][tag html][tag&bracket >]");
MT("list",
"[tag&bracket <][tag ol][tag&bracket >]",
" [tag&bracket <][tag li][tag&bracket >]one",
" [tag&bracket <][tag li][tag&bracket >]two",
"[tag&bracket </][tag ol][tag&bracket >]");
MT("valueless",
"[tag&bracket <][tag input] [attribute type]=[string checkbox] [attribute checked][tag&bracket />]");
MT("pThenArticle",
"[tag&bracket <][tag p][tag&bracket >]",
" foo",
"[tag&bracket <][tag article][tag&bracket >]bar");
})();

View File

@@ -0,0 +1,394 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var htmlConfig = {
autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
'track': true, 'wbr': true, 'menuitem': true},
implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
'th': true, 'tr': true},
contextGrabbers: {
'dd': {'dd': true, 'dt': true},
'dt': {'dd': true, 'dt': true},
'li': {'li': true},
'option': {'option': true, 'optgroup': true},
'optgroup': {'optgroup': true},
'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
'rp': {'rp': true, 'rt': true},
'rt': {'rp': true, 'rt': true},
'tbody': {'tbody': true, 'tfoot': true},
'td': {'td': true, 'th': true},
'tfoot': {'tbody': true},
'th': {'td': true, 'th': true},
'thead': {'tbody': true, 'tfoot': true},
'tr': {'tr': true}
},
doNotIndent: {"pre": true},
allowUnquoted: true,
allowMissing: true,
caseFold: true
}
var xmlConfig = {
autoSelfClosers: {},
implicitlyClosed: {},
contextGrabbers: {},
doNotIndent: {},
allowUnquoted: false,
allowMissing: false,
caseFold: false
}
CodeMirror.defineMode("xml", function(editorConf, config_) {
var indentUnit = editorConf.indentUnit
var config = {}
var defaults = config_.htmlMode ? htmlConfig : xmlConfig
for (var prop in defaults) config[prop] = defaults[prop]
for (var prop in config_) config[prop] = config_[prop]
// Return variables for tokenizers
var type, setStyle;
function inText(stream, state) {
function chain(parser) {
state.tokenize = parser;
return parser(stream, state);
}
var ch = stream.next();
if (ch == "<") {
if (stream.eat("!")) {
if (stream.eat("[")) {
if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
else return null;
} else if (stream.match("--")) {
return chain(inBlock("comment", "-->"));
} else if (stream.match("DOCTYPE", true, true)) {
stream.eatWhile(/[\w\._\-]/);
return chain(doctype(1));
} else {
return null;
}
} else if (stream.eat("?")) {
stream.eatWhile(/[\w\._\-]/);
state.tokenize = inBlock("meta", "?>");
return "meta";
} else {
type = stream.eat("/") ? "closeTag" : "openTag";
state.tokenize = inTag;
return "tag bracket";
}
} else if (ch == "&") {
var ok;
if (stream.eat("#")) {
if (stream.eat("x")) {
ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
} else {
ok = stream.eatWhile(/[\d]/) && stream.eat(";");
}
} else {
ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
}
return ok ? "atom" : "error";
} else {
stream.eatWhile(/[^&<]/);
return null;
}
}
inText.isInText = true;
function inTag(stream, state) {
var ch = stream.next();
if (ch == ">" || (ch == "/" && stream.eat(">"))) {
state.tokenize = inText;
type = ch == ">" ? "endTag" : "selfcloseTag";
return "tag bracket";
} else if (ch == "=") {
type = "equals";
return null;
} else if (ch == "<") {
state.tokenize = inText;
state.state = baseState;
state.tagName = state.tagStart = null;
var next = state.tokenize(stream, state);
return next ? next + " tag error" : "tag error";
} else if (/[\'\"]/.test(ch)) {
state.tokenize = inAttribute(ch);
state.stringStartCol = stream.column();
return state.tokenize(stream, state);
} else {
stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
return "word";
}
}
function inAttribute(quote) {
var closure = function(stream, state) {
while (!stream.eol()) {
if (stream.next() == quote) {
state.tokenize = inTag;
break;
}
}
return "string";
};
closure.isInAttribute = true;
return closure;
}
function inBlock(style, terminator) {
return function(stream, state) {
while (!stream.eol()) {
if (stream.match(terminator)) {
state.tokenize = inText;
break;
}
stream.next();
}
return style;
};
}
function doctype(depth) {
return function(stream, state) {
var ch;
while ((ch = stream.next()) != null) {
if (ch == "<") {
state.tokenize = doctype(depth + 1);
return state.tokenize(stream, state);
} else if (ch == ">") {
if (depth == 1) {
state.tokenize = inText;
break;
} else {
state.tokenize = doctype(depth - 1);
return state.tokenize(stream, state);
}
}
}
return "meta";
};
}
function Context(state, tagName, startOfLine) {
this.prev = state.context;
this.tagName = tagName;
this.indent = state.indented;
this.startOfLine = startOfLine;
if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
this.noIndent = true;
}
function popContext(state) {
if (state.context) state.context = state.context.prev;
}
function maybePopContext(state, nextTagName) {
var parentTagName;
while (true) {
if (!state.context) {
return;
}
parentTagName = state.context.tagName;
if (!config.contextGrabbers.hasOwnProperty(parentTagName) ||
!config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
return;
}
popContext(state);
}
}
function baseState(type, stream, state) {
if (type == "openTag") {
state.tagStart = stream.column();
return tagNameState;
} else if (type == "closeTag") {
return closeTagNameState;
} else {
return baseState;
}
}
function tagNameState(type, stream, state) {
if (type == "word") {
state.tagName = stream.current();
setStyle = "tag";
return attrState;
} else {
setStyle = "error";
return tagNameState;
}
}
function closeTagNameState(type, stream, state) {
if (type == "word") {
var tagName = stream.current();
if (state.context && state.context.tagName != tagName &&
config.implicitlyClosed.hasOwnProperty(state.context.tagName))
popContext(state);
if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {
setStyle = "tag";
return closeState;
} else {
setStyle = "tag error";
return closeStateErr;
}
} else {
setStyle = "error";
return closeStateErr;
}
}
function closeState(type, _stream, state) {
if (type != "endTag") {
setStyle = "error";
return closeState;
}
popContext(state);
return baseState;
}
function closeStateErr(type, stream, state) {
setStyle = "error";
return closeState(type, stream, state);
}
function attrState(type, _stream, state) {
if (type == "word") {
setStyle = "attribute";
return attrEqState;
} else if (type == "endTag" || type == "selfcloseTag") {
var tagName = state.tagName, tagStart = state.tagStart;
state.tagName = state.tagStart = null;
if (type == "selfcloseTag" ||
config.autoSelfClosers.hasOwnProperty(tagName)) {
maybePopContext(state, tagName);
} else {
maybePopContext(state, tagName);
state.context = new Context(state, tagName, tagStart == state.indented);
}
return baseState;
}
setStyle = "error";
return attrState;
}
function attrEqState(type, stream, state) {
if (type == "equals") return attrValueState;
if (!config.allowMissing) setStyle = "error";
return attrState(type, stream, state);
}
function attrValueState(type, stream, state) {
if (type == "string") return attrContinuedState;
if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;}
setStyle = "error";
return attrState(type, stream, state);
}
function attrContinuedState(type, stream, state) {
if (type == "string") return attrContinuedState;
return attrState(type, stream, state);
}
return {
startState: function(baseIndent) {
var state = {tokenize: inText,
state: baseState,
indented: baseIndent || 0,
tagName: null, tagStart: null,
context: null}
if (baseIndent != null) state.baseIndent = baseIndent
return state
},
token: function(stream, state) {
if (!state.tagName && stream.sol())
state.indented = stream.indentation();
if (stream.eatSpace()) return null;
type = null;
var style = state.tokenize(stream, state);
if ((style || type) && style != "comment") {
setStyle = null;
state.state = state.state(type || style, stream, state);
if (setStyle)
style = setStyle == "error" ? style + " error" : setStyle;
}
return style;
},
indent: function(state, textAfter, fullLine) {
var context = state.context;
// Indent multi-line strings (e.g. css).
if (state.tokenize.isInAttribute) {
if (state.tagStart == state.indented)
return state.stringStartCol + 1;
else
return state.indented + indentUnit;
}
if (context && context.noIndent) return CodeMirror.Pass;
if (state.tokenize != inTag && state.tokenize != inText)
return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
// Indent the starts of attribute names.
if (state.tagName) {
if (config.multilineTagIndentPastTag !== false)
return state.tagStart + state.tagName.length + 2;
else
return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1);
}
if (config.alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
if (tagAfter && tagAfter[1]) { // Closing tag spotted
while (context) {
if (context.tagName == tagAfter[2]) {
context = context.prev;
break;
} else if (config.implicitlyClosed.hasOwnProperty(context.tagName)) {
context = context.prev;
} else {
break;
}
}
} else if (tagAfter) { // Opening tag spotted
while (context) {
var grabbers = config.contextGrabbers[context.tagName];
if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
context = context.prev;
else
break;
}
}
while (context && context.prev && !context.startOfLine)
context = context.prev;
if (context) return context.indent + indentUnit;
else return state.baseIndent || 0;
},
electricInput: /<\/[\s\w:]+>$/,
blockCommentStart: "<!--",
blockCommentEnd: "-->",
configuration: config.htmlMode ? "html" : "xml",
helperType: config.htmlMode ? "html" : "xml",
skipAttribute: function(state) {
if (state.state == attrValueState)
state.state = attrState
}
};
});
CodeMirror.defineMIME("text/xml", "xml");
CodeMirror.defineMIME("application/xml", "xml");
if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
});

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

View File

@@ -0,0 +1,41 @@
.cm-s-mybb { font:13px/1.4em Trebuchet, Verdana, sans-serif; } /* - customized editor font - */
.cm-s-mybb.CodeMirror { background: #fafafa; color: black; height: 500px; width: 100%; max-width: 100%; }
.cm-s-mybb div.CodeMirror-selected { background: #b3c6d3 !important; }
.cm-s-mybb .CodeMirror-gutters { background: #1F4661; border-right: 7px solid #3E7087; }
.cm-s-mybb .CodeMirror-linenumber { color: white; }
.cm-s-mybb .CodeMirror-cursor { border-left: 1px solid black !important; }
.cm-s-mybb .CodeMirror-scroll { overflow-x: auto; }
.cm-s-mybb .cm-keyword {color: #708;}
.cm-s-mybb .cm-atom {color: #219;}
.cm-s-mybb .cm-number {color: #164;}
.cm-s-mybb .cm-def {color: #00f;}
.cm-s-mybb .cm-variable {color: black;}
.cm-s-mybb .cm-variable-2 {color: #05a;}
.cm-s-mybb .cm-variable-3 {color: #085;}
.cm-s-mybb .cm-property {color: black;}
.cm-s-mybb .cm-operator {color: black;}
.cm-s-mybb .cm-comment {color: #a50;}
.cm-s-mybb .cm-string {color: #a11;}
.cm-s-mybb .cm-string-2 {color: #f50;}
.cm-s-mybb .cm-meta {color: #555;}
.cm-s-mybb .cm-error {color: #f00;}
.cm-s-mybb .cm-qualifier {color: #555;}
.cm-s-mybb .cm-builtin {color: #30a;}
.cm-s-mybb .cm-bracket {color: #997;}
.cm-s-mybb .cm-tag {color: #170;}
.cm-s-mybb .cm-attribute {color: #00c;}
.cm-s-mybb .cm-header {color: blue;}
.cm-s-mybb .cm-quote {color: #090;}
.cm-s-mybb .cm-hr {color: #999;}
.cm-s-mybb .cm-link {color: #00c;}
.cm-negative {color: #d44;}
.cm-positive {color: #292;}
.cm-header, .cm-strong {font-weight: bold;}
.cm-em {font-style: italic;}
.cm-emstrong {font-style: italic; font-weight: bold;}
.cm-link {text-decoration: underline;}
.cm-invalidchar {color: #f00;}

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
/*! jQuery UI - v1.12.1 - 2017-07-24
* http://jqueryui.com
* Copyright jQuery Foundation and other contributors; Licensed MIT */
.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,57 @@
function MyCodeSandbox(url, button, regex_textbox, replacement_textbox, test_textbox, html_textbox, actual_div)
{
if(button && regex_textbox && replacement_textbox && test_textbox && html_textbox && actual_div)
{
this.url = url;
this.button = button;
this.regex_textbox = regex_textbox;
this.replacement_textbox = replacement_textbox;
this.test_textbox = test_textbox;
this.html_textbox = html_textbox;
this.actual_div = actual_div;
$(button).on('click', function(e) {
e.preventDefault();
this.update();
}.bind(this));
}
}
MyCodeSandbox.prototype.update = function(e)
{
postData = "regex="+encodeURIComponent($(this.regex_textbox).val())+"&replacement="+encodeURIComponent($(this.replacement_textbox).val())+"&test_value="+encodeURIComponent($(this.test_textbox).val())+"&my_post_key="+encodeURIComponent(my_post_key);
$.ajax(
{
url: this.url,
async: true,
method: 'post',
data: postData,
complete: function (request)
{
this.onComplete(request);
}.bind(this)
});
};
MyCodeSandbox.prototype.onComplete = function(request)
{
if(request.responseText.match(/<error>(.*)<\/error>/))
{
message = request.responseText.match(/<error>(.*)<\/error>/);
if(!message[1])
{
message[1] = lang.unknown_error;
}
alert(lang.mycode_sandbox_test_error + '\n\n' + message[1]);
}
else if(request.responseText)
{
$(this.actual_div).html(request.responseText);
$(this.html_textbox).val(request.responseText);
}
return true;
};

View File

@@ -0,0 +1,104 @@
/**
* Peeker controls the visibility of an element based on the value of an input
*
* Examples:
* new Peeker($('#myController'), $('#myDomain'), 1, false);
* new Peeker($('.myControllerNode'), $('#myDomain, #myDomain2'), 1, true);
* new Peeker($('#myController'), $('#nestedPeeker'), /works/, false);
* new Peeker($('#nestedPeeker'), $('#nestedPeekerChild'), /\d+/, false);
*/
var Peeker = (function() {
/**
* Constructor
*
* @param string ID of the controlling select menu
* @param string ID of the thing to show/hide
* @param regexp If this regexp matches value of the select menu, then the 'thing' will be shown
* @param boolean Should be set to true for radio/checkboxes
*/
function Peeker(controller, domain, match, isNodelist) {
var fn;
// verify input
if (!controller ||
(isNodelist && controller.length <= 0) ||
!domain) {
return;
}
this.controller = controller;
this.domain = domain;
this.match = match;
this.isNodelist = isNodelist;
// create a context-bound copy of the function
fn = $.proxy(this.check, this);
if (isNodelist) {
// attach event handlers to the inputs in the node list
this.controller.each(function(i, el) {
el = $(el);
el.on('click change', fn);
});
} else {
this.controller.on('change', fn);
}
this.check();
}
/**
* Checks the controller and shows/hide
*
* @return void
*/
function check() {
var type = '', show = false, regex = this.match;
if (this.isNodelist) {
this.controller.each(function(i, el) {
if ($(el).is(':visible') && el.checked &&
el.value.match(regex)) {
show = true;
return false;
}
});
this.domain[show ? 'show' : 'hide']();
} else {
type = this.controller.val() || '';
this.domain[(type.match(regex) && this.controller.is(':visible')) ? 'show' : 'hide']();
}
$(this.domain).each(function() {
$(this).find('input, textarea, select').each(function() {
$(this).trigger('change');
});
});
}
Peeker.prototype = {
controller: null,
domain: null,
match: null,
isNodelist: null,
check: check,
};
return Peeker;
})();
/**
* Add a "required" asterisk to a FormContainer row
* @param string ID of the row
*/
function add_star(id) {
if (!$('#' + id).length) {
return;
}
cell = $('#' + id).children('td')[0];
label = $(cell).children('label')[0];
star = $(document.createElement('em'));
starText = $(document.createTextNode(' *'));
star.append(starText);
$(label).append(star);
}

View File

@@ -0,0 +1,63 @@
var QuickPermEditor = {
init: function(id)
{
if(!$('#fields_enabled_'+id) || !$('#fields_disabled_'+id))
{
return;
}
if(!$('#fields_'+id))
{
return;
}
$("#fields_enabled_"+id).sortable({
connectWith: "#fields_disabled_"+id,
dropOnEmpty: true,
update: function(event, ui) {
QuickPermEditor.buildFieldsList(id);
}
}).disableSelection();
$("#fields_disabled_"+id).sortable({
connectWith: "#fields_enabled_"+id,
dropOnEmpty: true,
update: function(event, ui) {
QuickPermEditor.buildFieldsList(id);
}
}).disableSelection();
},
buildFieldsList: function(id)
{
new_input = '';
$('#fields_enabled_'+id).children().each(function() {
var textid = $(this).attr('id').split("-");
if(textid[1])
{
if(new_input)
{
new_input += ",";
}
new_input += textid[1];
}
});
if($('#fields_'+id).val() != new_input)
{
if($('#default_permissions_'+id))
{
$('#default_permissions_'+id).attr('checked', false);
}
}
$('#fields_'+id).val(new_input);
if($('#fields_inherit_'+id))
{
$('#fields_inherit_'+id).val(0);
}
},
};

View File

@@ -0,0 +1,73 @@
var SettingSearch = {
error_unknown : "",
init: function(settings_search, error_unknown)
{
this.error_unknown = error_unknown;
$('#settings_search').on("submit", this.onSubmit);
$('#search_results').css('display', 'none');
$('#search').focusin(function() {
if($('#search').val() == settings_search)
{
$('#search').removeClass('search_default');
$('#search').val('');
}
});
$('#search').focusout(function() {
if($('#search').val() == "")
{
$('#search').addClass('search_default');
$('#search').val(settings_search);
$("#search_results").css('display', "none");
$("#group_list").css('display', "");
}
});
},
onSubmit: function(e)
{
e.preventDefault();
if($('#search').val() != "")
{
$.jGrowl(lang.searching, {theme:'jgrowl_process'});
pars = "module=config-settings&action=change&ajax_search=1&search="+encodeURIComponent($('#search').val());
$.ajax({
type: 'get',
url: "index.php",
data: pars,
complete: function (request, status)
{
try
{
var json = JSON.parse(request.responseText);
if(typeof json == 'object')
{
if(json.hasOwnProperty("errors"))
{
$("div.jGrowl").jGrowl("close");
$.each(json.errors, function(i, message)
{
$.jGrowl(lang.search_error + ' ' + message, {theme:'jgrowl_error'});
});
return false;
}
}
}
catch(error)
{
$('#search_results').css('display', '');
$('#group_list').css('display', 'none');
$('#search_results').html(request.responseText);
$.jGrowl(lang.search_done, {theme:'jgrowl_success'});
return false;
}
}
});
}
},
};

View File

@@ -0,0 +1,43 @@
$(function()
{
$('ul.tabs').each(function()
{
if($(this).data('rendered'))
{
return;
}
$(this).data('rendered', 'yes');
var activeTab, activeContent, links = $(this).find('a');
activeTab = $(links.filter('[href="'+location.hash+'"]')[0] || links[0]);
activeTab.addClass('active');
activeContent = $(activeTab.attr('href'));
// Hide the remaining content
links.not(activeTab).each(function()
{
$($(this).attr('href')).hide();
});
// Tab functionality
$(this).on('click', 'a', function(e)
{
activeTab.removeClass('active');
activeContent.hide();
activeTab = $(this);
activeContent = $($(this).attr('href'));
// update address bar
window.location.hash = $(this).attr('href');
activeTab.addClass('active');
activeContent.show();
e.preventDefault();
});
});
});

View File

@@ -0,0 +1,87 @@
/**
* functions for stylesheet file/color attachments
*/
var themeProperties = (function() {
/**
* @var number the total attached files for this stylesheet
*/
var attachedCount = 0;
/**
* attach event handlers
*
* @return void
*/
function init() {
for (var i = 0; i < attachedCount; ++i) {
$("#delete_img_" + i).on('click', removeAttachmentBox);
}
$("#new_specific_file").on('click', addAttachmentBox);
}
/**
* allow external setup
*
* @param string the count at load time
* @return void
*/
function setup(count) {
attachedCount = count || 0;
}
/**
* create a new blank attachment box
*
* @param object the event
* @return void
*/
function addAttachmentBox(e) {
e.preventDefault();
var next_count = Number(attachedCount) + 1,
contents = "<div id=\"attached_form_" + attachedCount + "\"><div class=\"border_wrapper\">\n<table class=\"general form_container \" cellspacing=\"0\">\n<tbody>\n<tr class=\"first\">\n<td class=\"first\"><div class=\"form_row\"><span style=\"float: right;\"><a href=\"\" id=\"delete_img_" + attachedCount + "\"><img src=\"styles/default/images/icons/cross.png\" alt=\"" + delete_lang_string + "\" title=\"" + delete_lang_string + "\" /></a></span>" + file_lang_string + " &nbsp;<input type=\"text\" name=\"attached_" + attachedCount + "\" value=\"\" class=\"text_input\" style=\"width: 200px;\" id=\"attached_" + attachedCount + "\" /></div>\n</td>\n</tr>\n<tr class=\"last alt_row\">\n<td class=\"first\"><div class=\"form_row\"><dl style=\"margin-top: 0; margin-bottom: 0; width: 100%;\">\n<dt><label style=\"display: block;\"><input type=\"radio\" name=\"action_" + attachedCount + "\" value=\"0\" checked=\"checked\" class=\"action_" + attachedCount + "s_check\" onclick=\"checkAction('action_" + attachedCount + "');\" style=\"vertical-align: middle;\" /> " + globally_lang_string + "</label></dt>\n<dt><label style=\"display: block;\"><input type=\"radio\" name=\"action_" + attachedCount + "\" value=\"1\" class=\"action_" + attachedCount + "s_check\" onclick=\"checkAction('action_" + attachedCount + "');\" style=\"vertical-align: middle;\" /> " + specific_actions_lang_string + "</label></dt>\n<dd style=\"margin-top: 4px;\" id=\"action_" + attachedCount + "_1\" class=\"action_" + attachedCount + "s\">\n<small class=\"description\">" + specific_actions_desc_lang_string + "</small>\n<table cellpadding=\"4\">\n<tr>\n<td><input type=\"text\" name=\"action_list_" + attachedCount + "\" value=\"\" class=\"text_input\" style=\"width: 190px;\" id=\"action_list_" + attachedCount + "\" /></td>\n</tr>\n</table>\n</dd>\n</dl></div>\n</td>\n</tr>\n</tbody>\n</table>\n</div></div><div id=\"attach_box_" + next_count + "\"></div>\n";
// if this is the first attachment, create the first
if (!$("#attach_box_" + attachedCount).attr('id')) {
$("#attach_1").html(contents).show();
} else {
$("#attach_box_" + attachedCount).html(contents).show();
}
checkAction('action_' + attachedCount);
if ($("#attached_form_" + attachedCount)) {
$("#delete_img_" + attachedCount).on('click', removeAttachmentBox);
}
++attachedCount;
}
/**
* remove an entire attachment box
*
* @param object the event
* @return void
*/
function removeAttachmentBox(e) {
var idArray, id;
idArray = e.currentTarget.id.split('_');
if (!idArray.length) {
return;
}
id = idArray[idArray.length - 1];
e.preventDefault();
if (confirm(delete_confirm_lang_string) == true) {
$("#attached_form_" + id).remove();
}
}
$(init);
// the only public method
return {
setup: setup,
};
})();

View File

@@ -0,0 +1,345 @@
/**
* ThemeSelector loads various selectors' properties when they are select from
* a list
*/
var ThemeSelector = {
/**
* Constructor
*
* @param string the address to the load script
* @param string the address to the save script
* @param object the select element
* @param object the stylesheet info div
* @param string the stylesheet file name
* @param object the form element
* @param number the theme id
* @return void
*/
init: function(url, saveUrl, selector, styleSheet, file, selectorForm, tid) {
// verify input
if (!url || !saveUrl || !selector || !styleSheet || !file || !selectorForm || !tid) {
return;
}
ThemeSelector.url = url;
ThemeSelector.saveUrl = saveUrl;
ThemeSelector.selector = selector;
ThemeSelector.selectorPrevOpt = ThemeSelector.selector.val();
ThemeSelector.styleSheet = styleSheet;
ThemeSelector.file = file;
ThemeSelector.selectorForm = selectorForm;
ThemeSelector.tid = tid;
ThemeSelector.background = $("#css_bits\\[background\\]").val();
ThemeSelector.width = $("#css_bits\\[width\\]").val();
ThemeSelector.color = $("#css_bits\\[color\\]").val();
ThemeSelector.extra = $("#css_bits\\[extra\\]").val();
ThemeSelector.text_decoration = $("#css_bits\\[text_decoration\\]").val();
ThemeSelector.font_family = $("#css_bits\\[font_family\\]").val();
ThemeSelector.font_size = $("#css_bits\\[font_size\\]").val();
ThemeSelector.font_style = $("#css_bits\\[font_style\\]").val();
ThemeSelector.font_weight = $("#css_bits\\[font_weight\\]").val();
$("#save").on('click', function(event) { ThemeSelector.save(event, true); } );
$("#save_close").on('click', function(event) { ThemeSelector.saveClose(event); } );
$(window).on('beforeunload', function(event){
if(ThemeSelector.isChanged())
{
return ' ';
}
});
ThemeSelector.selector.on("change", ThemeSelector.updateSelector);
ThemeSelector.selectorForm.on("submit", ThemeSelector.updateSelector);
},
/**
* prevents no-save warning messaging when saving
*
* @return void
*/
saveClose: function(e) {
ThemeSelector.isClosing = true;
},
/**
* updates the stylesheet info to match the current selection, checking
* first that work isn't lost
*
* @param object the event
* @return void
*/
updateSelector: function(e) {
var postData;
e.preventDefault()
ThemeSelector.saveCheck(e, true);
postData = "file=" + encodeURIComponent(ThemeSelector.file) + "&tid=" + encodeURIComponent(ThemeSelector.tid) + "&selector=" + encodeURIComponent(ThemeSelector.selector.val()) + "&my_post_key=" + encodeURIComponent(my_post_key);
ThemeSelector.selectorGoText = $("#mini_spinner").html();
$("#mini_spinner").html("&nbsp;<img src=\"" + ThemeSelector.miniSpinnerImage + "\" style=\"vertical-align: middle;\" alt=\"\" /> ");
$.ajax({
type: 'post',
url: ThemeSelector.url,
data: postData,
complete: ThemeSelector.onComplete,
});
},
/**
* handles the AJAX return data
*
* @param object the request
* @return true
*/
onComplete: function(request) {
var message, saved;
if (request.responseText.match(/<error>(.*)<\/error>/)) {
message = request.responseText.match(/<error>(.*)<\/error>/);
if (!message[1]) {
message[1] = lang.unknown_error;
}
$.jGrowl(lang.theme_info_fetch_error + '\n\n' + message[1], {theme:'jgrowl_error'});
} else if(request.responseText) {
if ($("#saved").html()) {
saved = $("#saved").html();
}
ThemeSelector.styleSheet.html(request.responseText);
}
ThemeSelector.background = $("#css_bits\\[background\\]").val();
ThemeSelector.width = $("#css_bits\\[width\\]").val();
ThemeSelector.color = $("#css_bits\\[color\\]").val();
ThemeSelector.extra = $("#css_bits\\[extra\\]").val();
ThemeSelector.text_decoration = $("#css_bits\\[text_decoration\\]").val();
ThemeSelector.font_family = $("#css_bits\\[font_family\\]").val();
ThemeSelector.font_size = $("#css_bits\\[font_size\\]").val();
ThemeSelector.font_style = $("#css_bits\\[font_style\\]").val();
ThemeSelector.font_weight = $("#css_bits\\[font_weight\\]").val();
if (saved) {
$("#saved").html(saved);
window.setTimeout(function() {
$("#saved").html("");
}, 30000);
}
$("#mini_spinner").html(ThemeSelector.selectorGoText);
ThemeSelector.selectorGoText = '';
return true;
},
isChanged: function()
{
return (ThemeSelector.background != $("#css_bits\\[background\\]").val() ||
ThemeSelector.width != $("#css_bits\\[width\\]").val() ||
ThemeSelector.color != $("#css_bits\\[color\\]").val() ||
ThemeSelector.extra != $("#css_bits\\[extra\\]").val() ||
ThemeSelector.text_decoration != $("#css_bits\\[text_decoration\\]").val() ||
ThemeSelector.font_family != $("#css_bits\\[font_family\\]").val() ||
ThemeSelector.font_size != $("#css_bits\\[font_size\\]").val() ||
ThemeSelector.font_style != $("#css_bits\\[font_style\\]").val() ||
ThemeSelector.font_weight != $("#css_bits\\[font_weight\\]").val());
},
/**
* check if anything has changed
*
* @param object the event
* @param bool true if AJAX, false if not
* @return true
*/
saveCheck: function(e, isAjax) {
if (ThemeSelector.isClosing == true) {
return true;
}
if(e != null && isAjax == true)
e.preventDefault();
if (ThemeSelector.isChanged()) {
e.preventDefault();
if(isAjax == false)
return save_changes_lang_string;
else
{
confirmReturn = confirm(save_changes_lang_string);
if (confirmReturn == true) {
ThemeSelector.save(false, isAjax);
$.jGrowl(lang.saved, {theme:'jgrowl_success'});
}
}
}
else if(isAjax == true)
{
ThemeSelector.selectorPrevOpt = ThemeSelector.selector.val();
return true;
}
},
/**
* saves the selector info
*
* @param object the event
* @param bool true if AJAX, false if not
* @return true
*/
save: function(e, isAjax) {
var cssBits, postData, completeMethod = 'onUnloadSaveComplete';
if (e) {
e.preventDefault();
}
cssBits = {
'background': $('#css_bits\\[background\\]').val(),
'width': $('#css_bits\\[width\\]').val(),
'color': $('#css_bits\\[color\\]').val(),
'extra': $('#css_bits\\[extra\\]').val(),
'text_decoration': $('#css_bits\\[text_decoration\\]').val(),
'font_family': $('#css_bits\\[font_family\\]').val(),
'font_size': $('#css_bits\\[font_size\\]').val(),
'font_style': $('#css_bits\\[font_style\\]').val(),
'font_weight': $('#css_bits\\[font_weight\\]').val()
};
postData = "css_bits=" + encodeURIComponent(jsArrayToPhpArray(cssBits)) + "&selector=" + encodeURIComponent(ThemeSelector.selectorPrevOpt) + "&file=" + encodeURIComponent(ThemeSelector.file) + "&tid=" + encodeURIComponent(ThemeSelector.tid) + "&my_post_key=" + encodeURIComponent(my_post_key) + "&serialized=1";
if (isAjax == true) {
postData += "&ajax=1";
}
ThemeSelector.isAjax = isAjax;
if (isAjax == true) {
completeMethod = 'onSaveComplete';
$.jGrowl(lang.saving, {theme:'jgrowl_process'});
}
$.ajax({
type: 'post',
url: ThemeSelector.saveUrl,
data: postData,
complete: ThemeSelector[completeMethod],
});
return !isAjax;
},
/**
* handle errors, reset values and clean up
*
* @param object the request
* @return true
*/
onSaveComplete: function(request) {
var message;
if (request.responseText.match(/<error>(.*)<\/error>/)) {
message = request.responseText.match(/<error>(.*)<\/error>/);
if (!message[1]) {
message[1] = lang.unkown_error;
}
$.jGrowl(lang.theme_info_save_error + '\n\n' + message[1], {theme:'jgrowl_error'});
return false;
} else if(request.responseText) {
$("#saved").html(" (" + lang.saved + " @ "+ Date() + ")");
if ($("#ajax_alert")) {
$("#ajax_alert").html('').hide();
}
}
ThemeSelector.background = $("#css_bits\\[background\\]").val();
ThemeSelector.width = $("#css_bits\\[width\\]").val();
ThemeSelector.color = $("#css_bits\\[color\\]").val();
ThemeSelector.extra = $("#css_bits\\[extra\\]").val();
ThemeSelector.text_decoration = $("#css_bits\\[text_decoration\\]").val();
ThemeSelector.font_family = $("#css_bits\\[font_family\\]").val();
ThemeSelector.font_size = $("#css_bits\\[font_size\\]").val();
ThemeSelector.font_style = $("#css_bits\\[font_style\\]").val();
ThemeSelector.font_weight = $("#css_bits\\[font_weight\\]").val();
return true;
},
/**
* handle leaving page save
*
* @param object the request
* @return true
*/
onUnloadSaveComplete: function(request) {
var message;
if (request.responseText.match(/<error>(.*)<\/error>/)) {
message = request.responseText.match(/<error>(.*)<\/error>/);
if (!message[1]) {
message[1] = lang.unkown_error;
}
$.jGrowl(lang.theme_info_save_error + '\n\n' + message[1], {theme:'jgrowl_error'});
return false;
}
return true;
},
url: null,
saveUrl: null,
selector: null,
styleSheet: null,
file: null,
selectorForm: null,
tid: null,
miniSpinnerImage: "../images/spinner.gif",
isAjax: false,
specific_count: 0,
selectorGoText: null,
selectorPrevOpt: null,
isClosing: false,
background: null,
width: null,
color: null,
extra: null,
text_decoration: null,
font_family: null,
font_size: null,
font_style: null,
font_weight: null
};
/**
* converts a JS object to a JSON of a PHP associative array
*
* @param array the JS array
* @return string the JSON
*/
function jsArrayToPhpArray(a) {
var a_php = "", total = 0;
for (var key in a) {
++total;
a_php += "s:" +
String(key).length + ":\"" +
String(key) + "\";s:" +
String(a[key]).length +
":\"" + String(a[key]) + "\";";
}
a_php = "a:" + total + ":{" + a_php + "}";
return a_php;
}

View File

@@ -0,0 +1,13 @@
var Users = {
last_value: '',
cached_users: '',
init: function()
{
}
};
$(function()
{
Users.init();
});

View File

@@ -0,0 +1,53 @@
var ViewManager = {
init: function()
{
if(!$('#fields_enabled') || !$('#fields_disabled'))
{
return;
}
if(!$('#fields_js'))
{
return;
}
$("#fields_enabled").sortable({
connectWith: "#fields_disabled",
dropOnEmpty: true,
update: function(event, ui) {
ViewManager.buildFieldsList();
}
}).disableSelection();
$("#fields_disabled").sortable({
connectWith: "#fields_enabled",
dropOnEmpty: true,
update: function(event, ui) {
ViewManager.buildFieldsList();
}
}).disableSelection();
},
buildFieldsList: function()
{
new_input = '';
$('#fields_enabled').children().each(function() {
id = $(this).attr('id').split("-");
if(id[1])
{
if(new_input)
{
new_input += ",";
}
new_input += id[1];
}
});
$('#fields_js').val(new_input);
}
};
$(function()
{
ViewManager.init();
});

View File

@@ -0,0 +1,748 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
// Disallow direct access to this file for security reasons
if(!defined("IN_MYBB"))
{
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
}
$page->add_breadcrumb_item($lang->attachment_types, "index.php?module=config-attachment_types");
$plugins->run_hooks("admin_config_attachment_types_begin");
if($mybb->input['action'] == "add")
{
$plugins->run_hooks("admin_config_attachment_types_add");
if($mybb->request_method == "post")
{
if(!trim($mybb->input['mimetype']) && !trim($mybb->input['extension']))
{
$errors[] = $lang->error_missing_mime_type;
}
if(!trim($mybb->input['extension']) && !trim($mybb->input['mimetype']))
{
$errors[] = $lang->error_missing_extension;
}
if(!$errors)
{
if($mybb->input['mimetype'] == "images/attachtypes/")
{
$mybb->input['mimetype'] = '';
}
if(substr($mybb->input['extension'], 0, 1) == '.')
{
$mybb->input['extension'] = substr($mybb->input['extension'], 1);
}
foreach(array('groups', 'forums') as $key)
{
if($mybb->input[$key] == 'all')
{
$mybb->input[$key] = -1;
}
elseif($mybb->input[$key] == 'custom')
{
if(isset($mybb->input['select'][$key]) && is_array($mybb->input['select'][$key]))
{
foreach($mybb->input['select'][$key] as &$val)
{
$val = (int)$val;
}
unset($val);
$mybb->input[$key] = implode(',', (array)$mybb->input['select'][$key]);
}
else
{
$mybb->input[$key] = '';
}
}
else
{
$mybb->input[$key] = '';
}
}
$maxsize = $mybb->get_input('maxsize', MyBB::INPUT_INT);
if($maxsize == 0)
{
$maxsize = "";
}
$new_type = array(
"name" => $db->escape_string($mybb->input['name']),
"mimetype" => $db->escape_string($mybb->input['mimetype']),
"extension" => $db->escape_string($mybb->input['extension']),
"maxsize" => $maxsize,
"icon" => $db->escape_string($mybb->input['icon']),
'enabled' => $mybb->get_input('enabled', MyBB::INPUT_INT),
'groups' => $db->escape_string($mybb->get_input('groups')),
'forums' => $db->escape_string($mybb->get_input('forums')),
'avatarfile' => $mybb->get_input('avatarfile', MyBB::INPUT_INT)
);
$atid = $db->insert_query("attachtypes", $new_type);
$plugins->run_hooks("admin_config_attachment_types_add_commit");
// Log admin action
log_admin_action($atid, $mybb->input['extension']);
$cache->update_attachtypes();
flash_message($lang->success_attachment_type_created, 'success');
admin_redirect("index.php?module=config-attachment_types");
}
}
$page->add_breadcrumb_item($lang->add_new_attachment_type);
$page->output_header($lang->attachment_types." - ".$lang->add_new_attachment_type);
$sub_tabs['attachment_types'] = array(
'title' => $lang->attachment_types,
'link' => "index.php?module=config-attachment_types"
);
$sub_tabs['add_attachment_type'] = array(
'title' => $lang->add_new_attachment_type,
'link' => "index.php?module=config-attachment_types&amp;action=add",
'description' => $lang->add_attachment_type_desc
);
$page->output_nav_tabs($sub_tabs, 'add_attachment_type');
$form = new Form("index.php?module=config-attachment_types&amp;action=add", "post", "add");
if($errors)
{
switch($mybb->input['groups'])
{
case 'all':
$mybb->input['groups'] = -1;
break;
case 'custom':
$mybb->input['groups'] = implode(',', (array)$mybb->input['select']['groups']);
break;
default:
$mybb->input['groups'] = '';
break;
}
switch($mybb->input['forums'])
{
case 'all':
$mybb->input['forums'] = -1;
break;
case 'custom':
$mybb->input['forums'] = implode(',', (array)$mybb->input['select']['forums']);
break;
default:
$mybb->input['forums'] = '';
break;
}
$page->output_inline_error($errors);
}
else
{
$mybb->input['maxsize'] = '1024';
$mybb->input['icon'] = "images/attachtypes/";
}
if(empty($mybb->input['groups']))
{
$mybb->input['groups'] = '';
}
if(empty($mybb->input['forums']))
{
$mybb->input['forums'] = '';
}
// PHP settings
$upload_max_filesize = @ini_get('upload_max_filesize');
$post_max_size = @ini_get('post_max_size');
$limit_string = '';
if($upload_max_filesize || $post_max_size)
{
$limit_string = '<br /><br />'.$lang->limit_intro;
if($upload_max_filesize)
{
$limit_string .= '<br />'.$lang->sprintf($lang->limit_upload_max_filesize, $upload_max_filesize);
}
if($post_max_size)
{
$limit_string .= '<br />'.$lang->sprintf($lang->limit_post_max_size, $post_max_size);
}
}
$selected_values = '';
if($mybb->input['groups'] != '' && $mybb->input['groups'] != -1)
{
$selected_values = explode(',', $mybb->get_input('groups'));
foreach($selected_values as &$value)
{
$value = (int)$value;
}
unset($value);
}
$group_checked = array('all' => '', 'custom' => '', 'none' => '');
if($mybb->input['groups'] == -1)
{
$group_checked['all'] = 'checked="checked"';
}
elseif($mybb->input['groups'] != '')
{
$group_checked['custom'] = 'checked="checked"';
}
else
{
$group_checked['none'] = 'checked="checked"';
}
print_selection_javascript();
$groups_select_code = "
<dl style=\"margin-top: 0; margin-bottom: 0; width: 100%\">
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"groups\" value=\"all\" {$group_checked['all']} class=\"groups_forums_groups_check\" onclick=\"checkAction('groups');\" style=\"vertical-align: middle;\" /> <strong>{$lang->all_groups}</strong></label></dt>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"groups\" value=\"custom\" {$group_checked['custom']} class=\"groups_forums_groups_check\" onclick=\"checkAction('groups');\" style=\"vertical-align: middle;\" /> <strong>{$lang->select_groups}</strong></label></dt>
<dd style=\"margin-top: 4px;\" id=\"groups_forums_groups_custom\" class=\"groups_forums_groups\">
<table cellpadding=\"4\">
<tr>
<td valign=\"top\"><small>{$lang->groups_colon}</small></td>
<td>".$form->generate_group_select('select[groups][]', $selected_values, array('id' => 'groups', 'multiple' => true, 'size' => 5))."</td>
</tr>
</table>
</dd>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"groups\" value=\"none\" {$group_checked['none']} class=\"groups_forums_groups_check\" onclick=\"checkAction('groups');\" style=\"vertical-align: middle;\" /> <strong>{$lang->none}</strong></label></dt>
</dl>
<script type=\"text/javascript\">
checkAction('groups');
</script>";
$selected_values = '';
if($mybb->input['forums'] != '' && $mybb->input['forums'] != -1)
{
$selected_values = explode(',', $mybb->get_input('forums'));
foreach($selected_values as &$value)
{
$value = (int)$value;
}
unset($value);
}
$forum_checked = array('all' => '', 'custom' => '', 'none' => '');
if($mybb->input['forums'] == -1)
{
$forum_checked['all'] = 'checked="checked"';
}
elseif($mybb->input['forums'] != '')
{
$forum_checked['custom'] = 'checked="checked"';
}
else
{
$forum_checked['none'] = 'checked="checked"';
}
$forums_select_code = "
<dl style=\"margin-top: 0; margin-bottom: 0; width: 100%\">
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"forums\" value=\"all\" {$forum_checked['all']} class=\"forums_forums_groups_check\" onclick=\"checkAction('forums');\" style=\"vertical-align: middle;\" /> <strong>{$lang->all_forums}</strong></label></dt>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"forums\" value=\"custom\" {$forum_checked['custom']} class=\"forums_forums_groups_check\" onclick=\"checkAction('forums');\" style=\"vertical-align: middle;\" /> <strong>{$lang->select_forums}</strong></label></dt>
<dd style=\"margin-top: 4px;\" id=\"forums_forums_groups_custom\" class=\"forums_forums_groups\">
<table cellpadding=\"4\">
<tr>
<td valign=\"top\"><small>{$lang->forums_colon}</small></td>
<td>".$form->generate_forum_select('select[forums][]', $selected_values, array('id' => 'forums', 'multiple' => true, 'size' => 5))."</td>
</tr>
</table>
</dd>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"forums\" value=\"none\" {$forum_checked['none']} class=\"forums_forums_groups_check\" onclick=\"checkAction('forums');\" style=\"vertical-align: middle;\" /> <strong>{$lang->none}</strong></label></dt>
</dl>
<script type=\"text/javascript\">
checkAction('forums');
</script>";
$form_container = new FormContainer($lang->add_new_attachment_type);
$form_container->output_row($lang->name, $lang->name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name');
$form_container->output_row($lang->file_extension." <em>*</em>", $lang->file_extension_desc, $form->generate_text_box('extension', $mybb->input['extension'], array('id' => 'extension')), 'extension');
$form_container->output_row($lang->mime_type." <em>*</em>", $lang->mime_type_desc, $form->generate_text_box('mimetype', $mybb->input['mimetype'], array('id' => 'mimetype')), 'mimetype');
$form_container->output_row($lang->maximum_file_size, $lang->maximum_file_size_desc.$limit_string, $form->generate_numeric_field('maxsize', $mybb->input['maxsize'], array('id' => 'maxsize', 'min' => 0)), 'maxsize');
$form_container->output_row($lang->attachment_icon, $lang->attachment_icon_desc, $form->generate_text_box('icon', $mybb->input['icon'], array('id' => 'icon')), 'icon');
$form_container->output_row($lang->enabled, '', $form->generate_yes_no_radio('enabled', $mybb->input['enabled']), 'enabled');
$form_container->output_row($lang->available_to_groups, '', $groups_select_code, '', array(), array('id' => 'row_groups'));
$form_container->output_row($lang->available_in_forums, '', $forums_select_code, '', array(), array('id' => 'row_forums'));
$form_container->output_row($lang->avatar_file, $lang->avatar_file_desc, $form->generate_yes_no_radio('avatarfile', $mybb->input['avatarfile']), 'avatarfile');
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_attachment_type);
$form->output_submit_wrapper($buttons);
$form->end();
$page->output_footer();
}
if($mybb->input['action'] == "edit")
{
$query = $db->simple_select("attachtypes", "*", "atid='".$mybb->get_input('atid', MyBB::INPUT_INT)."'");
$attachment_type = $db->fetch_array($query);
if(!$attachment_type['atid'])
{
flash_message($lang->error_invalid_attachment_type, 'error');
admin_redirect("index.php?module=config-attachment_types");
}
$plugins->run_hooks("admin_config_attachment_types_edit");
if($mybb->request_method == "post")
{
if(!trim($mybb->input['mimetype']) && !trim($mybb->input['extension']))
{
$errors[] = $lang->error_missing_mime_type;
}
if(!trim($mybb->input['extension']) && !trim($mybb->input['mimetype']))
{
$errors[] = $lang->error_missing_extension;
}
if(!$errors)
{
if($mybb->input['mimetype'] == "images/attachtypes/")
{
$mybb->input['mimetype'] = '';
}
if(substr($mybb->input['extension'], 0, 1) == '.')
{
$mybb->input['extension'] = substr($mybb->input['extension'], 1);
}
foreach(array('groups', 'forums') as $key)
{
if($mybb->input[$key] == 'all')
{
$mybb->input[$key] = -1;
}
elseif($mybb->input[$key] == 'custom')
{
if(isset($mybb->input['select'][$key]) && is_array($mybb->input['select'][$key]))
{
foreach($mybb->input['select'][$key] as &$val)
{
$val = (int)$val;
}
unset($val);
$mybb->input[$key] = implode(',', (array)$mybb->input['select'][$key]);
}
else
{
$mybb->input[$key] = '';
}
}
else
{
$mybb->input[$key] = '';
}
}
$updated_type = array(
"name" => $db->escape_string($mybb->input['name']),
"mimetype" => $db->escape_string($mybb->input['mimetype']),
"extension" => $db->escape_string($mybb->input['extension']),
"maxsize" => $mybb->get_input('maxsize', MyBB::INPUT_INT),
"icon" => $db->escape_string($mybb->input['icon']),
'enabled' => $mybb->get_input('enabled', MyBB::INPUT_INT),
'groups' => $db->escape_string($mybb->get_input('groups')),
'forums' => $db->escape_string($mybb->get_input('forums')),
'avatarfile' => $mybb->get_input('avatarfile', MyBB::INPUT_INT)
);
$plugins->run_hooks("admin_config_attachment_types_edit_commit");
$db->update_query("attachtypes", $updated_type, "atid='{$attachment_type['atid']}'");
// Log admin action
log_admin_action($attachment_type['atid'], $mybb->input['extension']);
$cache->update_attachtypes();
flash_message($lang->success_attachment_type_updated, 'success');
admin_redirect("index.php?module=config-attachment_types");
}
}
$page->add_breadcrumb_item($lang->edit_attachment_type);
$page->output_header($lang->attachment_types." - ".$lang->edit_attachment_type);
$sub_tabs['edit_attachment_type'] = array(
'title' => $lang->edit_attachment_type,
'link' => "index.php?module=config-attachment_types&amp;action=edit&amp;atid={$attachment_type['atid']}",
'description' => $lang->edit_attachment_type_desc
);
$page->output_nav_tabs($sub_tabs, 'edit_attachment_type');
$form = new Form("index.php?module=config-attachment_types&amp;action=edit&amp;atid={$attachment_type['atid']}", "post", "add");
if($errors)
{
switch($mybb->input['groups'])
{
case 'all':
$mybb->input['groups'] = -1;
break;
case 'custom':
$mybb->input['groups'] = implode(',', (array)$mybb->input['select']['groups']);
break;
default:
$mybb->input['groups'] = '';
break;
}
switch($mybb->input['forums'])
{
case 'all':
$mybb->input['forums'] = -1;
break;
case 'custom':
$mybb->input['forums'] = implode(',', (array)$mybb->input['select']['forums']);
break;
default:
$mybb->input['forums'] = '';
break;
}
$page->output_inline_error($errors);
}
else
{
$mybb->input = array_merge($mybb->input, $attachment_type);
}
if(empty($mybb->input['groups']))
{
$mybb->input['groups'] = '';
}
if(empty($mybb->input['forums']))
{
$mybb->input['forums'] = '';
}
// PHP settings
$upload_max_filesize = @ini_get('upload_max_filesize');
$post_max_size = @ini_get('post_max_size');
$limit_string = '';
if($upload_max_filesize || $post_max_size)
{
$limit_string = '<br /><br />'.$lang->limit_intro;
if($upload_max_filesize)
{
$limit_string .= '<br />'.$lang->sprintf($lang->limit_upload_max_filesize, $upload_max_filesize);
}
if($post_max_size)
{
$limit_string .= '<br />'.$lang->sprintf($lang->limit_post_max_size, $post_max_size);
}
}
$selected_values = '';
if($mybb->input['groups'] != '' && $mybb->input['groups'] != -1)
{
$selected_values = explode(',', $mybb->get_input('groups'));
foreach($selected_values as &$value)
{
$value = (int)$value;
}
unset($value);
}
$group_checked = array('all' => '', 'custom' => '', 'none' => '');
if($mybb->input['groups'] == -1)
{
$group_checked['all'] = 'checked="checked"';
}
elseif($mybb->input['groups'] != '')
{
$group_checked['custom'] = 'checked="checked"';
}
else
{
$group_checked['none'] = 'checked="checked"';
}
print_selection_javascript();
$groups_select_code = "
<dl style=\"margin-top: 0; margin-bottom: 0; width: 100%\">
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"groups\" value=\"all\" {$group_checked['all']} class=\"groups_forums_groups_check\" onclick=\"checkAction('groups');\" style=\"vertical-align: middle;\" /> <strong>{$lang->all_groups}</strong></label></dt>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"groups\" value=\"custom\" {$group_checked['custom']} class=\"groups_forums_groups_check\" onclick=\"checkAction('groups');\" style=\"vertical-align: middle;\" /> <strong>{$lang->select_groups}</strong></label></dt>
<dd style=\"margin-top: 4px;\" id=\"groups_forums_groups_custom\" class=\"groups_forums_groups\">
<table cellpadding=\"4\">
<tr>
<td valign=\"top\"><small>{$lang->groups_colon}</small></td>
<td>".$form->generate_group_select('select[groups][]', $selected_values, array('id' => 'groups', 'multiple' => true, 'size' => 5))."</td>
</tr>
</table>
</dd>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"groups\" value=\"none\" {$group_checked['none']} class=\"groups_forums_groups_check\" onclick=\"checkAction('groups');\" style=\"vertical-align: middle;\" /> <strong>{$lang->none}</strong></label></dt>
</dl>
<script type=\"text/javascript\">
checkAction('groups');
</script>";
$selected_values = '';
if($mybb->input['forums'] != '' && $mybb->input['forums'] != -1)
{
$selected_values = explode(',', $mybb->get_input('forums'));
foreach($selected_values as &$value)
{
$value = (int)$value;
}
unset($value);
}
$forum_checked = array('all' => '', 'custom' => '', 'none' => '');
if($mybb->input['forums'] == -1)
{
$forum_checked['all'] = 'checked="checked"';
}
elseif($mybb->input['forums'] != '')
{
$forum_checked['custom'] = 'checked="checked"';
}
else
{
$forum_checked['none'] = 'checked="checked"';
}
$forums_select_code = "
<dl style=\"margin-top: 0; margin-bottom: 0; width: 100%\">
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"forums\" value=\"all\" {$forum_checked['all']} class=\"forums_forums_groups_check\" onclick=\"checkAction('forums');\" style=\"vertical-align: middle;\" /> <strong>{$lang->all_forums}</strong></label></dt>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"forums\" value=\"custom\" {$forum_checked['custom']} class=\"forums_forums_groups_check\" onclick=\"checkAction('forums');\" style=\"vertical-align: middle;\" /> <strong>{$lang->select_forums}</strong></label></dt>
<dd style=\"margin-top: 4px;\" id=\"forums_forums_groups_custom\" class=\"forums_forums_groups\">
<table cellpadding=\"4\">
<tr>
<td valign=\"top\"><small>{$lang->forums_colon}</small></td>
<td>".$form->generate_forum_select('select[forums][]', $selected_values, array('id' => 'forums', 'multiple' => true, 'size' => 5))."</td>
</tr>
</table>
</dd>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"forums\" value=\"none\" {$forum_checked['none']} class=\"forums_forums_groups_check\" onclick=\"checkAction('forums');\" style=\"vertical-align: middle;\" /> <strong>{$lang->none}</strong></label></dt>
</dl>
<script type=\"text/javascript\">
checkAction('forums');
</script>";
$form_container = new FormContainer($lang->edit_attachment_type);
$form_container->output_row($lang->name, $lang->name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name');
$form_container->output_row($lang->file_extension." <em>*</em>", $lang->file_extension_desc, $form->generate_text_box('extension', $mybb->input['extension'], array('id' => 'extension')), 'extension');
$form_container->output_row($lang->mime_type." <em>*</em>", $lang->mime_type_desc, $form->generate_text_box('mimetype', $mybb->input['mimetype'], array('id' => 'mimetype')), 'mimetype');
$form_container->output_row($lang->maximum_file_size, $lang->maximum_file_size_desc.$limit_string, $form->generate_numeric_field('maxsize', $mybb->input['maxsize'], array('id' => 'maxsize', 'min' => 0)), 'maxsize');
$form_container->output_row($lang->attachment_icon, $lang->attachment_icon_desc, $form->generate_text_box('icon', $mybb->input['icon'], array('id' => 'icon')), 'icon');
$form_container->output_row($lang->enabled, '', $form->generate_yes_no_radio('enabled', $mybb->input['enabled']), 'enabled');
$form_container->output_row($lang->available_to_groups, '', $groups_select_code, '', array(), array('id' => 'row_groups'));
$form_container->output_row($lang->available_in_forums, '', $forums_select_code, '', array(), array('id' => 'row_forums'));
$form_container->output_row($lang->avatar_file, $lang->avatar_file_desc, $form->generate_yes_no_radio('avatarfile', $mybb->input['avatarfile']), 'avatarfile');
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_attachment_type);
$form->output_submit_wrapper($buttons);
$form->end();
$page->output_footer();
}
if($mybb->input['action'] == "delete")
{
if($mybb->input['no'])
{
admin_redirect("index.php?module=config-attachment_types");
}
$query = $db->simple_select("attachtypes", "*", "atid='".$mybb->get_input('atid', MyBB::INPUT_INT)."'");
$attachment_type = $db->fetch_array($query);
if(!$attachment_type['atid'])
{
flash_message($lang->error_invalid_attachment_type, 'error');
admin_redirect("index.php?module=config-attachment_types");
}
$plugins->run_hooks("admin_config_attachment_types_delete");
if($mybb->request_method == "post")
{
$db->delete_query("attachtypes", "atid='{$attachment_type['atid']}'");
$plugins->run_hooks("admin_config_attachment_types_delete_commit");
$cache->update_attachtypes();
// Log admin action
log_admin_action($attachment_type['atid'], $attachment_type['extension']);
flash_message($lang->success_attachment_type_deleted, 'success');
admin_redirect("index.php?module=config-attachment_types");
}
else
{
$page->output_confirm_action("index.php?module=config-attachment_types&amp;action=delete&amp;atid={$attachment_type['atid']}", $lang->confirm_attachment_type_deletion);
}
}
if($mybb->input['action'] == 'toggle_status')
{
if(!verify_post_check($mybb->input['my_post_key']))
{
flash_message($lang->invalid_post_verify_key2, 'error');
admin_redirect('index.php?module=config-attachment_types');
}
$atid = $mybb->get_input('atid', MyBB::INPUT_INT);
$query = $db->simple_select('attachtypes', '*', "atid='{$atid}'");
$attachment_type = $db->fetch_array($query);
if(!$attachment_type['atid'])
{
flash_message($lang->error_invalid_mycode, 'error');
admin_redirect('index.php?module=config-attachment_types');
}
$plugins->run_hooks('admin_config_attachment_types_toggle_status');
$update_array = array('enabled' => 1);
$phrase = $lang->success_activated_attachment_type;
if($attachment_type['enabled'] == 1)
{
$update_array['enabled'] = 0;
$phrase = $lang->success_activated_attachment_type;
}
$plugins->run_hooks('admin_config_attachment_types_toggle_status_commit');
$db->update_query('attachtypes', $update_array, "atid='{$atid}'");
$cache->update_attachtypes();
// Log admin action
log_admin_action($atid, $attachment_type['extension'], $update_array['enabled']);
flash_message($phrase, 'success');
admin_redirect('index.php?module=config-attachment_types');
}
if(!$mybb->input['action'])
{
$page->output_header($lang->attachment_types);
$sub_tabs['attachment_types'] = array(
'title' => $lang->attachment_types,
'link' => "index.php?module=config-attachment_types",
'description' => $lang->attachment_types_desc
);
$sub_tabs['add_attachment_type'] = array(
'title' => $lang->add_new_attachment_type,
'link' => "index.php?module=config-attachment_types&amp;action=add",
);
$plugins->run_hooks("admin_config_attachment_types_start");
$page->output_nav_tabs($sub_tabs, 'attachment_types');
$table = new Table;
$table->construct_header($lang->extension, array("colspan" => 2));
$table->construct_header($lang->mime_type);
$table->construct_header($lang->alt_enabled, array('class' => 'align_center'));
$table->construct_header($lang->maximum_size, array("class" => "align_center"));
$table->construct_header($lang->controls, array("class" => "align_center"));
$query = $db->simple_select("attachtypes", "*", "", array('order_by' => 'extension'));
while($attachment_type = $db->fetch_array($query))
{
// Just show default icons in ACP
$attachment_type['icon'] = htmlspecialchars_uni(str_replace("{theme}", "images", $attachment_type['icon']));
if(my_validate_url($attachment_type['icon'], true))
{
$image = $attachment_type['icon'];
}
else
{
$image = "../".$attachment_type['icon'];
}
if(!$attachment_type['icon'] || $attachment_type['icon'] == "images/attachtypes/")
{
$attachment_type['icon'] = "&nbsp;";
}
else
{
$attachment_type['name'] = htmlspecialchars_uni($attachment_type['name']);
$attachment_type['icon'] = "<img src=\"{$image}\" title=\"{$attachment_type['name']}\" alt=\"\" />";
}
if($attachment_type['enabled'])
{
$phrase = $lang->disable;
$icon = "on.png\" alt=\"({$lang->alt_enabled})\" title=\"{$lang->alt_enabled}";
}
else
{
$phrase = $lang->enable;
$icon = "off.png\" alt=\"({$lang->alt_disabled})\" title=\"{$lang->alt_disabled}";
}
$attachment_type['extension'] = htmlspecialchars_uni($attachment_type['extension']);
$table->construct_cell($attachment_type['icon'], array("width" => 1));
$table->construct_cell("<strong>.{$attachment_type['extension']}</strong>");
$table->construct_cell(htmlspecialchars_uni($attachment_type['mimetype']));
$table->construct_cell("<img src=\"styles/{$page->style}/images/icons/bullet_{$icon}\" style=\"vertical-align: middle;\" />", array("class" => "align_center"));
$table->construct_cell(get_friendly_size(($attachment_type['maxsize']*1024)), array("class" => "align_center"));
$popup = new PopupMenu("attachment_type_{$attachment_type['atid']}", $lang->options);
$popup->add_item($lang->edit, "index.php?module=config-attachment_types&amp;action=edit&amp;atid={$attachment_type['atid']}");
$popup->add_item($phrase, "index.php?module=config-attachment_types&amp;action=toggle_status&amp;atid={$attachment_type['atid']}&amp;my_post_key={$mybb->post_code}");
$popup->add_item($lang->delete, "index.php?module=config-attachment_types&amp;action=delete&amp;atid={$attachment_type['atid']}&amp;my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_attachment_type_deletion}')");
$table->construct_cell($popup->fetch(), array('class' => 'align_center'));
$table->construct_row();
}
if($table->num_rows() == 0)
{
$table->construct_cell($lang->no_attachment_types, array('colspan' => 6));
$table->construct_row();
}
$table->output($lang->attachment_types);
$page->output_footer();
}

View File

@@ -0,0 +1,301 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
// Disallow direct access to this file for security reasons
if(!defined("IN_MYBB"))
{
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
}
$page->add_breadcrumb_item($lang->bad_words, "index.php?module=config-badwords");
$plugins->run_hooks("admin_config_badwords_begin");
if($mybb->input['action'] == "add" && $mybb->request_method == "post")
{
$plugins->run_hooks("admin_config_badwords_add");
if(!trim($mybb->input['badword']))
{
$errors[] = $lang->error_missing_bad_word;
}
if(strlen(trim($mybb->input['badword'])) > 100)
{
$errors[] = $lang->bad_word_max;
}
if(strlen($mybb->input['replacement']) > 100)
{
$errors[] = $lang->replacement_word_max;
}
if(!$errors)
{
$query = $db->simple_select("badwords", "bid", "badword = '".$db->escape_string($mybb->input['badword'])."'");
if($db->num_rows($query))
{
$errors[] = $lang->error_bad_word_filtered;
}
}
$badword = trim($mybb->input['badword']);
if($mybb->get_input('regex', MyBB::INPUT_INT))
{
// Check validity of defined regular expression
if((@preg_match('#'.$badword.'#is', null) === false))
{
$errors[] = $lang->error_invalid_regex;
}
}
else
{
if(!is_object($parser))
{
require_once MYBB_ROOT."inc/class_parser.php";
$parser = new postParser;
}
$badword = $parser->generate_regex($badword);
}
// Don't allow certain badword replacements to be added if it would cause an infinite recursive loop.
if(@preg_match('#'.$badword.'#is', $mybb->input['replacement']))
{
$errors[] = $lang->error_replacement_word_invalid;
}
if(!$errors)
{
$new_badword = array(
"badword" => $db->escape_string($mybb->input['badword']),
"regex" => $mybb->get_input('regex', MyBB::INPUT_INT),
"replacement" => $db->escape_string($mybb->input['replacement'])
);
$bid = $db->insert_query("badwords", $new_badword);
$plugins->run_hooks("admin_config_badwords_add_commit");
// Log admin action
log_admin_action($bid, $mybb->input['badword']);
$cache->update_badwords();
flash_message($lang->success_added_bad_word, 'success');
admin_redirect("index.php?module=config-badwords");
}
else
{
$mybb->input['action'] = '';
}
}
if($mybb->input['action'] == "delete")
{
$query = $db->simple_select("badwords", "*", "bid='".$mybb->get_input('bid', MyBB::INPUT_INT)."'");
$badword = $db->fetch_array($query);
// Does the bad word not exist?
if(!$badword['bid'])
{
flash_message($lang->error_invalid_bid, 'error');
admin_redirect("index.php?module=config-badwords");
}
// User clicked no
if($mybb->input['no'])
{
admin_redirect("index.php?module=config-badwords");
}
$plugins->run_hooks("admin_config_badwords_delete");
if($mybb->request_method == "post")
{
// Delete the bad word
$db->delete_query("badwords", "bid='{$badword['bid']}'");
$plugins->run_hooks("admin_config_badwords_delete_commit");
// Log admin action
log_admin_action($badword['bid'], $badword['badword']);
$cache->update_badwords();
flash_message($lang->success_deleted_bad_word, 'success');
admin_redirect("index.php?module=config-badwords");
}
else
{
$page->output_confirm_action("index.php?module=config-badwords&action=delete&bid={$badword['bid']}", $lang->confirm_bad_word_deletion);
}
}
if($mybb->input['action'] == "edit")
{
$query = $db->simple_select("badwords", "*", "bid='".$mybb->get_input('bid', MyBB::INPUT_INT)."'");
$badword = $db->fetch_array($query);
// Does the bad word not exist?
if(!$badword['bid'])
{
flash_message($lang->error_invalid_bid, 'error');
admin_redirect("index.php?module=config-badwords");
}
$plugins->run_hooks("admin_config_badwords_edit");
if($mybb->request_method == "post")
{
if(!trim($mybb->input['badword']))
{
$errors[] = $lang->error_missing_bad_word;
}
if(strlen(trim($mybb->input['badword'])) > 100)
{
$errors[] = $lang->bad_word_max;
}
if(strlen($mybb->input['replacement']) > 100)
{
$errors[] = $lang->replacement_word_max;
}
if(!$errors)
{
$updated_badword = array(
"badword" => $db->escape_string($mybb->input['badword']),
"regex" => $mybb->get_input('regex', MyBB::INPUT_INT),
"replacement" => $db->escape_string($mybb->input['replacement'])
);
$plugins->run_hooks("admin_config_badwords_edit_commit");
$db->update_query("badwords", $updated_badword, "bid='{$badword['bid']}'");
// Log admin action
log_admin_action($badword['bid'], $mybb->input['badword']);
$cache->update_badwords();
flash_message($lang->success_updated_bad_word, 'success');
admin_redirect("index.php?module=config-badwords");
}
}
$page->add_breadcrumb_item($lang->edit_bad_word);
$page->output_header($lang->bad_words." - ".$lang->edit_bad_word);
$sub_tabs['editbadword'] = array(
'title' => $lang->edit_bad_word,
'description' => $lang->edit_bad_word_desc,
'link' => "index.php?module=config-badwords"
);
$page->output_nav_tabs($sub_tabs, "editbadword");
$form = new Form("index.php?module=config-badwords&amp;action=edit&amp;bid={$badword['bid']}", "post");
if($errors)
{
$page->output_inline_error($errors);
$badword_data = $mybb->input;
}
else
{
$badword_data = $badword;
}
$form_container = new FormContainer($lang->edit_bad_word);
$form_container->output_row($lang->bad_word." <em>*</em>", $lang->bad_word_desc, $form->generate_text_box('badword', $badword_data['badword'], array('id' => 'badword')), 'badword');
$form_container->output_row($lang->replacement, $lang->replacement_desc, $form->generate_text_box('replacement', $badword_data['replacement'], array('id' => 'replacement')), 'replacement');
$form_container->output_row($lang->regex, $lang->regex_desc, $form->generate_yes_no_radio('regex', (int)$badword_data['regex'], array('id' => 'regex')), 'regex');
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_bad_word);
$form->output_submit_wrapper($buttons);
$form->end();
$page->output_footer();
}
if(!$mybb->input['action'])
{
$page->output_header($lang->bad_words);
$sub_tabs['badwords'] = array(
'title' => $lang->bad_word_filters,
'description' => $lang->bad_word_filters_desc,
'link' => "index.php?module=config-badwords"
);
$plugins->run_hooks("admin_config_badwords_start");
$page->output_nav_tabs($sub_tabs, "badwords");
if($errors)
{
$page->output_inline_error($errors);
}
$table = new Table;
$table->construct_header($lang->bad_word);
$table->construct_header($lang->replacement, array("width" => "50%"));
$table->construct_header($lang->regex, array("class" => "align_center", "width" => "20%"));
$table->construct_header($lang->controls, array("class" => "align_center", "width" => 150, "colspan" => 2));
$query = $db->simple_select("badwords", "*", "", array("order_by" => "badword", "order_dir" => "asc"));
while($badword = $db->fetch_array($query))
{
$badword['badword'] = htmlspecialchars_uni($badword['badword']);
$badword['replacement'] = htmlspecialchars_uni($badword['replacement']);
if(!$badword['replacement'])
{
$badword['replacement'] = '*****';
}
$regex = $lang->no;
if($badword['regex'])
{
$regex = $lang->yes;
}
$table->construct_cell($badword['badword']);
$table->construct_cell($badword['replacement']);
$table->construct_cell($regex, array("class" => "align_center"));
$table->construct_cell("<a href=\"index.php?module=config-badwords&amp;action=edit&amp;bid={$badword['bid']}\">{$lang->edit}</a>", array("class" => "align_center"));
$table->construct_cell("<a href=\"index.php?module=config-badwords&amp;action=delete&amp;bid={$badword['bid']}&amp;my_post_key={$mybb->post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_bad_word_deletion}');\">{$lang->delete}</a>", array("class" => "align_center"));
$table->construct_row();
}
if($table->num_rows() == 0)
{
$table->construct_cell($lang->no_bad_words, array("colspan" => 4));
$table->construct_row();
}
$table->output($lang->bad_word_filters);
$form = new Form("index.php?module=config-badwords&amp;action=add", "post", "add");
$form_container = new FormContainer($lang->add_bad_word);
$form_container->output_row($lang->bad_word." <em>*</em>", $lang->bad_word_desc, $form->generate_text_box('badword', $mybb->input['badword'], array('id' => 'badword')), 'badword');
$form_container->output_row($lang->replacement, $lang->replacement_desc, $form->generate_text_box('replacement', $mybb->input['replacement'], array('id' => 'replacement')), 'replacement');
$form_container->output_row($lang->regex, $lang->regex_desc, $form->generate_yes_no_radio('regex', !$mybb->get_input('regex'), array('id' => 'regex')), 'regex');
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_bad_word);
$form->output_submit_wrapper($buttons);
$form->end();
$page->output_footer();
}

View File

@@ -0,0 +1,296 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
// Disallow direct access to this file for security reasons
if(!defined("IN_MYBB"))
{
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
}
$page->add_breadcrumb_item($lang->banning, "index.php?module=config-banning");
$plugins->run_hooks("admin_config_banning_begin");
if($mybb->input['action'] == "add" && $mybb->request_method == "post")
{
$plugins->run_hooks("admin_config_banning_add");
if(!trim($mybb->input['filter']))
{
$errors[] = $lang->error_missing_ban_input;
}
$query = $db->simple_select("banfilters", "fid", "filter = '".$db->escape_string($mybb->input['filter'])."' AND type = '".$mybb->get_input('type', MyBB::INPUT_INT)."'");
if($db->num_rows($query))
{
$errors[] = $lang->error_filter_already_banned;
}
if(!$errors)
{
$new_filter = array(
"filter" => $db->escape_string($mybb->input['filter']),
"type" => $mybb->get_input('type', MyBB::INPUT_INT),
"dateline" => TIME_NOW
);
$fid = $db->insert_query("banfilters", $new_filter);
$plugins->run_hooks("admin_config_banning_add_commit");
if($mybb->input['type'] == 1)
{
$cache->update_bannedips();
}
else if($mybb->input['type'] == 3)
{
$cache->update_bannedemails();
}
// Log admin action
log_admin_action($fid, $mybb->input['filter'], (int)$mybb->input['type']);
if($mybb->input['type'] == 1)
{
flash_message($lang->success_ip_banned, 'success');
admin_redirect("index.php?module=config-banning");
}
else if($mybb->input['type'] == 2)
{
flash_message($lang->success_username_disallowed, 'success');
admin_redirect("index.php?module=config-banning&type=usernames");
}
else if($mybb->input['type'] == 3)
{
flash_message($lang->success_email_disallowed, 'success');
admin_redirect("index.php?module=config-banning&type=emails");
}
}
else
{
if($mybb->input['type'] == 1)
{
$mybb->input['type'] = "ips";
}
else if($mybb->input['type'] == 2)
{
$mybb->input['type'] = "usernames";
}
else if($mybb->input['type'] == 3)
{
$mybb->input['type'] = "emails";
}
$mybb->input['action'] = '';
}
}
if($mybb->input['action'] == "delete")
{
$query = $db->simple_select("banfilters", "*", "fid='".$mybb->get_input('fid', MyBB::INPUT_INT)."'");
$filter = $db->fetch_array($query);
// Does the filter not exist?
if(!$filter['fid'])
{
flash_message($lang->error_invalid_filter, 'error');
admin_redirect("index.php?module=config-banning");
}
$plugins->run_hooks("admin_config_banning_delete");
if($filter['type'] == 3)
{
$type = "emails";
}
else if($filter['type'] == 2)
{
$type = "usernames";
}
else
{
$type = "ips";
}
// User clicked no
if($mybb->input['no'])
{
admin_redirect("index.php?module=config-banning&type={$type}");
}
if($mybb->request_method == "post")
{
// Delete the ban filter
$db->delete_query("banfilters", "fid='{$filter['fid']}'");
$plugins->run_hooks("admin_config_banning_delete_commit");
// Log admin action
log_admin_action($filter['fid'], $filter['filter'], (int)$filter['type']);
// Banned IP? Rebuild banned IP cache
if($filter['type'] == 1)
{
$cache->update_bannedips();
}
else if($filter['type'] == 3)
{
$cache->update_bannedemails();
}
flash_message($lang->success_ban_deleted, 'success');
admin_redirect("index.php?module=config-banning&type={$type}");
}
else
{
$page->output_confirm_action("index.php?module=config-banning&amp;action=delete&amp;fid={$filter['fid']}", $lang->confirm_ban_deletion);
}
}
if(!$mybb->input['action'])
{
$plugins->run_hooks("admin_config_banning_start");
switch($mybb->input['type'])
{
case "emails":
$type = "3";
$title = $lang->disallowed_email_addresses;
break;
case "usernames":
$type = "2";
$title = $lang->disallowed_usernames;
break;
default:
$type = "1";
$title = $lang->banned_ip_addresses;
$mybb->input['type'] = "ips";
}
$page->output_header($title);
$sub_tabs['ips'] = array(
'title' => $lang->banned_ips,
'link' => "index.php?module=config-banning",
'description' => $lang->banned_ips_desc
);
$sub_tabs['users'] = array(
'title' => $lang->banned_accounts,
'link' => "index.php?module=user-banning"
);
$sub_tabs['usernames'] = array(
'title' => $lang->disallowed_usernames,
'link' => "index.php?module=config-banning&amp;type=usernames",
'description' => $lang->disallowed_usernames_desc
);
$sub_tabs['emails'] = array(
'title' => $lang->disallowed_email_addresses,
'link' => "index.php?module=config-banning&amp;type=emails",
'description' => $lang->disallowed_email_addresses_desc
);
$page->output_nav_tabs($sub_tabs, $mybb->input['type']);
if($errors)
{
$page->output_inline_error($errors);
}
$form = new Form("index.php?module=config-banning&amp;action=add", "post", "add");
if($mybb->input['type'] == "usernames")
{
$form_container = new FormContainer($lang->add_disallowed_username);
$form_container->output_row($lang->username." <em>*</em>", $lang->username_desc, $form->generate_text_box('filter', $mybb->input['filter'], array('id' => 'filter')), 'filter');
$buttons[] = $form->generate_submit_button($lang->disallow_username);
}
else if($mybb->input['type'] == "emails")
{
$form_container = new FormContainer($lang->add_disallowed_email_address);
$form_container->output_row($lang->email_address." <em>*</em>", $lang->email_address_desc, $form->generate_text_box('filter', $mybb->input['filter'], array('id' => 'filter')), 'filter');
$buttons[] = $form->generate_submit_button($lang->disallow_email_address);
}
else
{
$form_container = new FormContainer($lang->ban_an_ip_address);
$form_container->output_row($lang->ip_address." <em>*</em>", $lang->ip_address_desc, $form->generate_text_box('filter', $mybb->input['filter'], array('id' => 'filter')), 'filter');
$buttons[] = $form->generate_submit_button($lang->ban_ip_address);
}
$form_container->end();
echo $form->generate_hidden_field("type", $type);
$form->output_submit_wrapper($buttons);
$form->end();
echo '<br />';
$table = new Table;
if($mybb->input['type'] == "usernames")
{
$table->construct_header($lang->username);
$table->construct_header($lang->date_disallowed, array("class" => "align_center", "width" => 200));
$table->construct_header($lang->last_attempted_use, array("class" => "align_center", "width" => 200));
}
else if($mybb->input['type'] == "emails")
{
$table->construct_header($lang->email_address);
$table->construct_header($lang->date_disallowed, array("class" => "align_center", "width" => 200));
$table->construct_header($lang->last_attempted_use, array("class" => "align_center", "width" => 200));
}
else
{
$table->construct_header($lang->ip_address);
$table->construct_header($lang->ban_date, array("class" => "align_center", "width" => 200));
$table->construct_header($lang->last_access, array("class" => "align_center", "width" => 200));
}
$table->construct_header($lang->controls, array("width" => 1));
$query = $db->simple_select("banfilters", "*", "type='{$type}'", array("order_by" => "filter", "order_dir" => "asc"));
while($filter = $db->fetch_array($query))
{
$filter['filter'] = htmlspecialchars_uni($filter['filter']);
if($filter['lastuse'] > 0)
{
$last_use = my_date('relative', $filter['lastuse']);
}
else
{
$last_use = $lang->never;
}
if($filter['dateline'] > 0)
{
$date = my_date('relative', $filter['dateline']);
}
else
{
$date = $lang->na;
}
$table->construct_cell($filter['filter']);
$table->construct_cell($date, array("class" => "align_center"));
$table->construct_cell($last_use, array("class" => "align_center"));
$table->construct_cell("<a href=\"index.php?module=config-banning&amp;action=delete&amp;fid={$filter['fid']}&amp;my_post_key={$mybb->post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_ban_deletion}');\"><img src=\"styles/{$page->style}/images/icons/delete.png\" title=\"{$lang->delete}\" alt=\"{$lang->delete}\" /></a>", array("class" => "align_center"));
$table->construct_row();
}
if($table->num_rows() == 0)
{
$table->construct_cell($lang->no_bans, array("colspan" => 4));
$table->construct_row();
}
$table->output($title);
$page->output_footer();
}

View File

@@ -0,0 +1,479 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
// Disallow direct access to this file for security reasons
if(!defined("IN_MYBB"))
{
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
}
$page->add_breadcrumb_item($lang->calendars, "index.php?module=config-calendars");
if($mybb->input['action'] == "add" || $mybb->input['action'] == "permissions" || !$mybb->input['action'])
{
$sub_tabs['manage_calendars'] = array(
'title' => $lang->manage_calendars,
'link' => "index.php?module=config-calendars",
'description' => $lang->manage_calendars_desc
);
$sub_tabs['add_calendar'] = array(
'title' => $lang->add_calendar,
'link' => "index.php?module=config-calendars&amp;action=add",
'description' => $lang->add_calendar_desc
);
}
$plugins->run_hooks("admin_config_calendars_begin");
if($mybb->input['action'] == "add")
{
$plugins->run_hooks("admin_config_calendars_add");
if($mybb->request_method == "post")
{
$plugins->run_hooks("admin_config_calendars_add_commit");
if(!trim($mybb->input['name']))
{
$errors[] = $lang->error_missing_name;
}
if(!isset($mybb->input['disporder']))
{
$errors[] = $lang->error_missing_order;
}
if(!$errors)
{
$calendar = array(
"name" => $db->escape_string($mybb->input['name']),
"disporder" => $mybb->get_input('disporder', MyBB::INPUT_INT),
"startofweek" => $mybb->get_input('startofweek', MyBB::INPUT_INT),
"eventlimit" => $mybb->get_input('eventlimit', MyBB::INPUT_INT),
"showbirthdays" => $mybb->get_input('showbirthdays', MyBB::INPUT_INT),
"moderation" => $mybb->get_input('moderation', MyBB::INPUT_INT),
"allowhtml" => $mybb->get_input('allowhtml', MyBB::INPUT_INT),
"allowmycode" => $mybb->get_input('allowmycode', MyBB::INPUT_INT),
"allowimgcode" => $mybb->get_input('allowimgcode', MyBB::INPUT_INT),
"allowvideocode" => $mybb->get_input('allowvideocode', MyBB::INPUT_INT),
"allowsmilies" => $mybb->get_input('allowsmilies', MyBB::INPUT_INT)
);
$plugins->run_hooks("admin_config_calendars_add_commit_start");
$cid = $db->insert_query("calendars", $calendar);
$plugins->run_hooks("admin_config_calendars_add_commit_end");
// Log admin action
log_admin_action($cid, $mybb->input['name']);
flash_message($lang->success_calendar_created, 'success');
admin_redirect("index.php?module=config-calendars");
}
}
else
{
$mybb->input = array_merge($mybb->input, array(
"allowhtml" => 0,
"eventlimit" => 4,
"disporder" => 1,
"moderation" => 0
)
);
}
$page->add_breadcrumb_item($lang->add_calendar);
$page->output_header($lang->calendars." - ".$lang->add_calendar);
$page->output_nav_tabs($sub_tabs, 'add_calendar');
$form = new Form("index.php?module=config-calendars&amp;action=add", "post");
if($errors)
{
$page->output_inline_error($errors);
}
$form_container = new FormContainer($lang->add_calendar);
$form_container->output_row($lang->name." <em>*</em>", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name');
$form_container->output_row($lang->display_order, $lang->display_order_desc, $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder', 'min' => 0)), 'disporder');
$select_list = array($lang->sunday, $lang->monday, $lang->tuesday, $lang->wednesday, $lang->thursday, $lang->friday, $lang->saturday);
$form_container->output_row($lang->week_start, $lang->week_start_desc, $form->generate_select_box('startofweek', $select_list, $mybb->input['startofweek'], array('id' => 'startofweek')), 'startofweek');
$form_container->output_row($lang->event_limit, $lang->event_limit_desc, $form->generate_numeric_field('eventlimit', $mybb->input['eventlimit'], array('id' => 'eventlimit', 'min' => 0)), 'eventlimit');
$form_container->output_row($lang->show_birthdays, $lang->show_birthdays_desc, $form->generate_yes_no_radio('showbirthdays', $mybb->input['showbirthdays'], true));
$form_container->output_row($lang->moderate_events, $lang->moderate_events_desc, $form->generate_yes_no_radio('moderation', $mybb->input['moderation'], true));
$form_container->output_row($lang->allow_html, "", $form->generate_yes_no_radio('allowhtml', $mybb->input['allowhtml']));
$form_container->output_row($lang->allow_mycode, "", $form->generate_yes_no_radio('allowmycode', $mybb->input['allowmycode']));
$form_container->output_row($lang->allow_img, "", $form->generate_yes_no_radio('allowimgcode', $mybb->input['allowimgcode']));
$form_container->output_row($lang->allow_video, "", $form->generate_yes_no_radio('allowvideocode', $mybb->input['allowvideocode']));
$form_container->output_row($lang->allow_smilies, "", $form->generate_yes_no_radio('allowsmilies', $mybb->input['allowsmilies']));
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_calendar);
$form->output_submit_wrapper($buttons);
$form->end();
$page->output_footer();
}
if($mybb->input['action'] == "permissions")
{
$usergroups = array();
$query = $db->simple_select("calendars", "*", "cid='".$mybb->get_input('cid', MyBB::INPUT_INT)."'");
$calendar = $db->fetch_array($query);
// Does the calendar not exist?
if(!$calendar['cid'])
{
flash_message($lang->error_invalid_calendar, 'error');
admin_redirect("index.php?module=config-calendars");
}
$plugins->run_hooks("admin_config_calendars_permissions");
$query = $db->simple_select("usergroups", "*", "", array("order" => "name"));
while($usergroup = $db->fetch_array($query))
{
$usergroups[$usergroup['gid']] = $usergroup;
}
$query = $db->simple_select("calendarpermissions", "*", "cid='{$calendar['cid']}'");
while($existing = $db->fetch_array($query))
{
$existing_permissions[$existing['gid']] = $existing;
}
if($mybb->request_method == "post")
{
foreach(array_keys($usergroups) as $group_id)
{
$permissions = $mybb->input['permissions'][$group_id];
$db->delete_query("calendarpermissions", "cid='{$calendar['cid']}' AND gid='".(int)$group_id."'");
if(!$mybb->input['default_permissions'][$group_id])
{
foreach(array('canviewcalendar','canaddevents','canbypasseventmod','canmoderateevents') as $calendar_permission)
{
if($permissions[$calendar_permission] == 1)
{
$permissions_array[$calendar_permission] = 1;
}
else
{
$permissions_array[$calendar_permission] = 0;
}
}
$permissions_array['gid'] = (int)$group_id;
$permissions_array['cid'] = $calendar['cid'];
$db->insert_query("calendarpermissions", $permissions_array);
}
}
$plugins->run_hooks("admin_config_calendars_permissions_commit");
// Log admin action
log_admin_action($calendar['cid'], $calendar['name']);
flash_message($lang->success_calendar_permissions_updated, 'success');
admin_redirect("index.php?module=config-calendars");
}
$calendar['name'] = htmlspecialchars_uni($calendar['name']);
$page->add_breadcrumb_item($calendar['name'], "index.php?module=config-calendars&amp;action=edit&amp;cid={$calendar['cid']}");
$page->add_breadcrumb_item($lang->permissions);
$page->output_header($lang->calendars." - ".$lang->edit_permissions);
$form = new Form("index.php?module=config-calendars&amp;action=permissions", "post");
echo $form->generate_hidden_field("cid", $calendar['cid']);
$table = new Table;
$table->construct_header($lang->permissions_group);
$table->construct_header($lang->permissions_view, array("class" => "align_center", "width" => "10%"));
$table->construct_header($lang->permissions_post_events, array("class" => "align_center", "width" => "10%"));
$table->construct_header($lang->permissions_bypass_moderation, array("class" => "align_center", "width" => "10%"));
$table->construct_header($lang->permissions_moderator, array("class" => "align_center", "width" => "10%"));
$table->construct_header($lang->permissions_all, array("class" => "align_center", "width" => "10%"));
foreach($usergroups as $usergroup)
{
if($existing_permissions[$usergroup['gid']])
{
$perms = $existing_permissions[$usergroup['gid']];
$default_checked = false;
}
else
{
$perms = $usergroup;
$default_checked = true;
}
$perm_check = $all_check = "";
$all_checked = true;
foreach(array('canviewcalendar','canaddevents','canbypasseventmod','canmoderateevents') as $calendar_permission)
{
if($usergroup[$calendar_permission] == 1)
{
$value = "this.checked";
}
else
{
$value = "false";
}
if($perms[$calendar_permission] != 1)
{
$all_checked = false;
}
if($perms[$calendar_permission] == 1)
{
$perms_checked[$calendar_permission] = 1;
}
else
{
$perms_checked[$calendar_permission] = 0;
}
$all_check .= "\$('#permissions_{$usergroup['gid']}_{$calendar_permission}').prop('checked', this.checked);\n";
$perm_check .= "\$('#permissions_{$usergroup['gid']}_{$calendar_permission}').prop('checked', $value);\n";
}
$default_click = "if(\$(this).is(':checked')) { $perm_check }";
$reset_default = "if(!\$(this).is(':checked')) { \$('#permissions_{$usergroup['gid']}_all').prop('checked', false); }\n";
$usergroup['title'] = htmlspecialchars_uni($usergroup['title']);
$table->construct_cell("<strong>{$usergroup['title']}</strong><br /><small style=\"vertical-align: middle;\">".$form->generate_check_box("default_permissions[{$usergroup['gid']}];", 1, "", array("id" => "default_permissions_{$usergroup['gid']}", "checked" => $default_checked, "onclick" => $default_click))." <label for=\"default_permissions_{$usergroup['gid']}\">{$lang->permissions_use_group_default}</label></small>");
$table->construct_cell($form->generate_check_box("permissions[{$usergroup['gid']}][canviewcalendar]", 1, "", array("id" => "permissions_{$usergroup['gid']}_canviewcalendar", "checked" => $perms_checked['canviewcalendar'], "onclick" => $reset_default)), array('class' => 'align_center'));
$table->construct_cell($form->generate_check_box("permissions[{$usergroup['gid']}][canaddevents]", 1, "", array("id" => "permissions_{$usergroup['gid']}_canaddevents", "checked" => $perms_checked['canaddevents'], "onclick" => $reset_default)), array('class' => 'align_center'));
$table->construct_cell($form->generate_check_box("permissions[{$usergroup['gid']}][canbypasseventmod]", 1, "", array("id" => "permissions_{$usergroup['gid']}_canbypasseventmod", "checked" => $perms_checked['canbypasseventmod'], "onclick" => $reset_default)), array('class' => 'align_center'));
$table->construct_cell($form->generate_check_box("permissions[{$usergroup['gid']}][canmoderateevents]", 1, "", array("id" => "permissions_{$usergroup['gid']}_canmoderateevents", "checked" => $perms_checked['canmoderateevents'], "onclick" => $reset_default)), array('class' => 'align_center'));
$table->construct_cell($form->generate_check_box("permissions[{$usergroup['gid']}][all]", 1, "", array("id" => "permissions_{$usergroup['gid']}_all", "checked" => $all_checked, "onclick" => $all_check)), array('class' => 'align_center'));
$table->construct_row();
}
$table->output("{$lang->calendar_permissions_for} {$calendar['name']}");
if(!$no_results)
{
$buttons[] = $form->generate_submit_button($lang->save_permissions);
$form->output_submit_wrapper($buttons);
}
$form->end();
$page->output_footer();
}
if($mybb->input['action'] == "edit")
{
$query = $db->simple_select("calendars", "*", "cid='".$mybb->get_input('cid', MyBB::INPUT_INT)."'");
$calendar = $db->fetch_array($query);
// Does the calendar not exist?
if(!$calendar['cid'])
{
flash_message($lang->error_invalid_calendar, 'error');
admin_redirect("index.php?module=config-calendars");
}
$plugins->run_hooks("admin_config_calendars_edit");
if($mybb->request_method == "post")
{
if(!trim($mybb->input['name']))
{
$errors[] = $lang->error_missing_name;
}
if(!isset($mybb->input['disporder']))
{
$errors[] = $lang->error_missing_order;
}
if(!$errors)
{
$updated_calendar = array(
"name" => $db->escape_string($mybb->input['name']),
"disporder" => $mybb->get_input('disporder', MyBB::INPUT_INT),
"startofweek" => $mybb->get_input('startofweek', MyBB::INPUT_INT),
"eventlimit" => $mybb->get_input('eventlimit', MyBB::INPUT_INT),
"showbirthdays" => $mybb->get_input('showbirthdays', MyBB::INPUT_INT),
"moderation" => $mybb->get_input('moderation', MyBB::INPUT_INT),
"allowhtml" => $mybb->get_input('allowhtml', MyBB::INPUT_INT),
"allowmycode" => $mybb->get_input('allowmycode', MyBB::INPUT_INT),
"allowimgcode" => $mybb->get_input('allowimgcode', MyBB::INPUT_INT),
"allowvideocode" => $mybb->get_input('allowvideocode', MyBB::INPUT_INT),
"allowsmilies" => $mybb->get_input('allowsmilies', MyBB::INPUT_INT)
);
$plugins->run_hooks("admin_config_calendars_edit_commit");
$db->update_query("calendars", $updated_calendar, "cid='{$calendar['cid']}'");
// Log admin action
log_admin_action($calendar['cid'], $mybb->input['name']);
flash_message($lang->success_calendar_updated, 'success');
admin_redirect("index.php?module=config-calendars");
}
}
$page->add_breadcrumb_item($lang->edit_calendar);
$page->output_header($lang->calendars." - ".$lang->edit_calendar);
$sub_tabs['edit_calendar'] = array(
'title' => $lang->edit_calendar,
'link' => "index.php?module=config-calendars&amp;action=edit",
'description' => $lang->edit_calendar_desc
);
$page->output_nav_tabs($sub_tabs, 'edit_calendar');
$form = new Form("index.php?module=config-calendars&amp;action=edit", "post");
echo $form->generate_hidden_field("cid", $calendar['cid']);
if($errors)
{
$page->output_inline_error($errors);
}
else
{
$mybb->input = $calendar;
}
$form_container = new FormContainer($lang->edit_calendar);
$form_container->output_row($lang->name." <em>*</em>", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name');
$form_container->output_row($lang->display_order." <em>*</em>", $lang->display_order_desc, $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder', 'min' => 0)), 'disporder');
$select_list = array($lang->sunday, $lang->monday, $lang->tuesday, $lang->wednesday, $lang->thursday, $lang->friday, $lang->saturday);
$form_container->output_row($lang->week_start, $lang->week_start_desc, $form->generate_select_box('startofweek', $select_list, $mybb->input['startofweek'], array('id' => 'startofweek')), 'startofweek');
$form_container->output_row($lang->event_limit, $lang->event_limit_desc, $form->generate_numeric_field('eventlimit', $mybb->input['eventlimit'], array('id' => 'eventlimit', 'min' => 0)), 'eventlimit');
$form_container->output_row($lang->show_birthdays, $lang->show_birthdays_desc, $form->generate_yes_no_radio('showbirthdays', $mybb->input['showbirthdays'], true));
$form_container->output_row($lang->moderate_events, $lang->moderate_events_desc, $form->generate_yes_no_radio('moderation', $mybb->input['moderation'], true));
$form_container->output_row($lang->allow_html, "", $form->generate_yes_no_radio('allowhtml', $mybb->input['allowhtml']));
$form_container->output_row($lang->allow_mycode, "", $form->generate_yes_no_radio('allowmycode', $mybb->input['allowmycode']));
$form_container->output_row($lang->allow_img, "", $form->generate_yes_no_radio('allowimgcode', $mybb->input['allowimgcode']));
$form_container->output_row($lang->allow_video, "", $form->generate_yes_no_radio('allowvideocode', $mybb->input['allowvideocode']));
$form_container->output_row($lang->allow_smilies, "", $form->generate_yes_no_radio('allowsmilies', $mybb->input['allowsmilies']));
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_calendar);
$form->output_submit_wrapper($buttons);
$form->end();
$page->output_footer();
}
if($mybb->input['action'] == "delete")
{
$query = $db->simple_select("calendars", "*", "cid='".$mybb->get_input('cid', MyBB::INPUT_INT)."'");
$calendar = $db->fetch_array($query);
// Does the calendar not exist?
if(!$calendar['cid'])
{
flash_message($lang->error_invalid_calendar, 'error');
admin_redirect("index.php?module=config-calendars");
}
$plugins->run_hooks("admin_config_calendars_delete");
// User clicked no
if($mybb->input['no'])
{
admin_redirect("index.php?module=config-calendars");
}
if($mybb->request_method == "post")
{
// Delete the calendar
$db->delete_query("calendars", "cid='{$calendar['cid']}'");
$db->delete_query("calendarpermissions", "cid='{$calendar['cid']}'");
$db->delete_query("events", "cid='{$calendar['cid']}'");
$plugins->run_hooks("admin_config_calendars_delete_commit");
// Log admin action
log_admin_action($calendar['cid'], $calendar['name']);
flash_message($lang->success_calendar_deleted, 'success');
admin_redirect("index.php?module=config-calendars");
}
else
{
$page->output_confirm_action("index.php?module=config-calendars&amp;action=delete&amp;cid={$calendar['cid']}", $lang->confirm_calendar_deletion);
}
}
if($mybb->input['action'] == "update_order" && $mybb->request_method == "post")
{
if(!is_array($mybb->input['disporder']))
{
admin_redirect("index.php?module=config-calendars");
}
$plugins->run_hooks("admin_config_calendars_update_order");
foreach($mybb->input['disporder'] as $cid => $order)
{
$update_query = array(
"disporder" => (int)$order
);
$db->update_query("calendars", $update_query, "cid='".(int)$cid."'");
}
$plugins->run_hooks("admin_config_calendars_update_order_commit");
// Log admin action
log_admin_action();
flash_message($lang->success_calendar_orders_updated, 'success');
admin_redirect("index.php?module=config-calendars");
}
if(!$mybb->input['action'])
{
$page->output_header($lang->manage_calendars);
$page->output_nav_tabs($sub_tabs, 'manage_calendars');
$form = new Form("index.php?module=config-calendars&amp;action=update_order", "post");
$table = new Table;
$table->construct_header($lang->calendar);
$table->construct_header($lang->order, array('width' => '5%', 'class' => 'align_center'));
$table->construct_header($lang->controls, array("class" => "align_center", "colspan" => 3, "width" => 300));
$query = $db->simple_select("calendars", "*", "", array('order_by' => 'disporder'));
while($calendar = $db->fetch_array($query))
{
$calendar['name'] = htmlspecialchars_uni($calendar['name']);
$table->construct_cell("<a href=\"index.php?module=config-calendars&amp;action=edit&amp;cid={$calendar['cid']}\"><strong>{$calendar['name']}</strong></a>");
$table->construct_cell($form->generate_numeric_field("disporder[{$calendar['cid']}]", $calendar['disporder'], array('id' => 'disporder', 'style' => 'width: 80%', 'class' => 'align_center', 'min' => 0)));
$table->construct_cell("<a href=\"index.php?module=config-calendars&amp;action=edit&amp;cid={$calendar['cid']}\">{$lang->edit}</a>", array("width" => 100, "class" => "align_center"));
$table->construct_cell("<a href=\"index.php?module=config-calendars&amp;action=permissions&amp;cid={$calendar['cid']}\">{$lang->permissions}</a>", array("width" => 100, "class" => "align_center"));
$table->construct_cell("<a href=\"index.php?module=config-calendars&amp;action=delete&amp;cid={$calendar['cid']}&amp;my_post_key={$mybb->post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_calendar_deletion}')\">{$lang->delete}</a>", array("width" => 100, "class" => "align_center"));
$table->construct_row();
}
if($table->num_rows() == 0)
{
$table->construct_cell($lang->no_calendars, array('colspan' => 5));
$table->construct_row();
$no_results = true;
}
$table->output($lang->manage_calendars);
if(!$no_results)
{
$buttons[] = $form->generate_submit_button($lang->save_calendar_orders);
$form->output_submit_wrapper($buttons);
}
$form->end();
$page->output_footer();
}

View File

@@ -0,0 +1,624 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
// Disallow direct access to this file for security reasons
if(!defined("IN_MYBB"))
{
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
}
$page->add_breadcrumb_item($lang->help_documents, "index.php?module=config-help_documents");
$plugins->run_hooks("admin_config_help_documents_begin");
// Add something
if($mybb->input['action'] == "add")
{
$plugins->run_hooks("admin_config_help_documents_add");
// Add section
if($mybb->input['type'] == "section")
{
$plugins->run_hooks("admin_config_help_documents_add_section");
// Do add?
if($mybb->request_method == "post")
{
if(empty($mybb->input['name']))
{
$errors[] = $lang->error_section_missing_name;
}
if(empty($mybb->input['description']))
{
$errors[] = $lang->error_section_missing_description;
}
if(!isset($mybb->input['enabled']))
{
$errors[] = $lang->error_section_missing_enabled;
}
if($mybb->input['enabled'] != 1)
{
$mybb->input['enabled'] = 0;
}
if(!is_array($errors))
{
$sql_array = array(
"name" => $db->escape_string($mybb->input['name']),
"description" => $db->escape_string($mybb->input['description']),
"usetranslation" => $mybb->get_input('usetranslation', MyBB::INPUT_INT),
"enabled" => $mybb->get_input('enabled', MyBB::INPUT_INT),
"disporder" => $mybb->get_input('disporder', MyBB::INPUT_INT)
);
$sid = $db->insert_query("helpsections", $sql_array);
$plugins->run_hooks("admin_config_help_documents_add_section_commit");
// Log admin action
log_admin_action($sid, $mybb->input['name'], 'section');
flash_message($lang->success_help_section_added, 'success');
admin_redirect('index.php?module=config-help_documents');
}
}
$page->add_breadcrumb_item($lang->add_new_section);
$page->output_header($lang->help_documents." - ".$lang->add_new_section);
$sub_tabs['manage_help_documents'] = array(
'title' => $lang->manage_help_documents,
'link' => "index.php?module=config-help_documents"
);
$sub_tabs['add_help_document'] = array(
'title' => $lang->add_new_document,
'link' => "index.php?module=config-help_documents&amp;action=add&amp;type=document"
);
$sub_tabs['add_help_section'] = array(
'title' => $lang->add_new_section,
'link' => "index.php?module=config-help_documents&amp;action=add&amp;type=section",
'description' => $lang->add_new_section_desc
);
$page->output_nav_tabs($sub_tabs, 'add_help_section');
if($errors)
{
$page->output_inline_error($errors);
}
else
{
$query = $db->simple_select("helpsections", "MAX(disporder) as maxdisp");
$mybb->input['disporder'] = $db->fetch_field($query, "maxdisp")+1;
$mybb->input['enabled'] = 1;
$mybb->input['usetranslation'] = 1;
}
$form = new Form("index.php?module=config-help_documents&amp;action=add&amp;type=section", "post", "add");
echo $form->generate_hidden_field("usetranslation", $mybb->input['usetranslation']);
$form_container = new FormContainer($lang->add_new_section);
$form_container->output_row($lang->title." <em>*</em>", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name');
$form_container->output_row($lang->short_description." <em>*</em>", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description');
$form_container->output_row($lang->display_order, "", $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder', 'min' => 0)), 'disporder');
$form_container->output_row($lang->enabled." <em>*</em>", "", $form->generate_yes_no_radio('enabled', $mybb->input['enabled']));
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_section);
$form->output_submit_wrapper($buttons);
$form->end();
}
// Add page
else
{
$plugins->run_hooks("admin_config_help_documents_add_page");
// Do add?
if($mybb->request_method == "post")
{
if(empty($mybb->input['sid']))
{
$errors[] = $lang->error_missing_sid;
}
if(empty($mybb->input['name']))
{
$errors[] = $lang->error_document_missing_name;
}
if(empty($mybb->input['description']))
{
$errors[] = $lang->error_document_missing_description;
}
if(empty($mybb->input['document']))
{
$errors[] = $lang->error_document_missing_document;
}
if(!isset($mybb->input['enabled']))
{
$errors[] = $lang->error_document_missing_enabled;
}
if($mybb->input['enabled'] != 1)
{
$mybb->input['enabled'] = 0;
}
if(!is_array($errors))
{
$sql_array = array(
"sid" => $mybb->get_input('sid', MyBB::INPUT_INT),
"name" => $db->escape_string($mybb->input['name']),
"description" => $db->escape_string($mybb->input['description']),
"document" => $db->escape_string($mybb->input['document']),
"usetranslation" => $mybb->get_input('usetranslation', MyBB::INPUT_INT),
"enabled" => $mybb->get_input('enabled', MyBB::INPUT_INT),
"disporder" => $mybb->get_input('disporder', MyBB::INPUT_INT)
);
$hid = $db->insert_query("helpdocs", $sql_array);
$plugins->run_hooks("admin_config_help_documents_add_page_commit");
// Log admin action
log_admin_action($hid, $mybb->input['name'], 'document');
flash_message($lang->success_help_document_added, 'success');
admin_redirect('index.php?module=config-help_documents');
}
}
$page->add_breadcrumb_item($lang->add_new_document);
$page->output_header($lang->help_documents." - ".$lang->add_new_document);
$sub_tabs['manage_help_documents'] = array(
'title' => $lang->manage_help_documents,
'link' => "index.php?module=config-help_documents"
);
$sub_tabs['add_help_document'] = array(
'title' => $lang->add_new_document,
'link' => "index.php?module=config-help_documents&amp;action=add&amp;type=document",
'description' => $lang->add_new_document_desc
);
$sub_tabs['add_help_section'] = array(
'title' => $lang->add_new_section,
'link' => "index.php?module=config-help_documents&amp;action=add&amp;type=section"
);
$page->output_nav_tabs($sub_tabs, 'add_help_document');
if($errors)
{
$page->output_inline_error($errors);
}
else
{
// Select the largest existing display order
$query = $db->simple_select("helpdocs", "MAX(disporder) as maxdisp");
$mybb->input['disporder'] = $db->fetch_field($query, "maxdisp")+1;
$mybb->input['enabled'] = 1;
$mybb->input['usetranslation'] = 1;
}
$form = new Form("index.php?module=config-help_documents&amp;action=add&amp;type=document", "post", "add");
echo $form->generate_hidden_field("usetranslation", $mybb->input['usetranslation']);
$form_container = new FormContainer($lang->add_new_document);
$query = $db->simple_select("helpsections", "sid, name");
$sections = array();
while($section = $db->fetch_array($query))
{
$sections[$section['sid']] = $section['name'];
}
$form_container->output_row($lang->section." <em>*</em>", "", $form->generate_select_box("sid", $sections, $mybb->input['sid'], array('id' => 'sid')), 'sid');
$form_container->output_row($lang->title." <em>*</em>", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name');
$form_container->output_row($lang->short_description." <em>*</em>", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description');
$form_container->output_row($lang->document." <em>*</em>", "", $form->generate_text_area('document', $mybb->input['document'], array('id' => 'document')), 'document');
$form_container->output_row($lang->display_order, "", $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder', 'min' => 0)), 'disporder');
$form_container->output_row($lang->enabled." <em>*</em>", "", $form->generate_yes_no_radio('enabled', $mybb->input['enabled']));
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_document);
$form->output_submit_wrapper($buttons);
$form->end();
}
$page->output_footer();
}
// Edit something
if($mybb->input['action'] == "edit")
{
$plugins->run_hooks("admin_config_help_documents_edit");
// Edit a section
if($mybb->input['sid'] && !$mybb->input['hid'])
{
$query = $db->simple_select("helpsections", "*", "sid = '".$mybb->get_input('sid', MyBB::INPUT_INT)."'");
$section = $db->fetch_array($query);
$plugins->run_hooks("admin_config_help_documents_edit_section");
// Do edit?
if($mybb->request_method == "post")
{
$sid = $mybb->get_input('sid', MyBB::INPUT_INT);
if(empty($sid))
{
$errors[] = $lang->error_invalid_sid;
}
if(empty($mybb->input['name']))
{
$errors[] = $lang->error_section_missing_name;
}
if(empty($mybb->input['description']))
{
$errors[] = $lang->error_section_missing_description;
}
if(!isset($mybb->input['enabled']))
{
$errors[] = $lang->error_section_missing_enabled;
}
if($mybb->input['enabled'] != 1)
{
$mybb->input['enabled'] = 0;
}
if(!is_array($errors))
{
$sql_array = array(
"name" => $db->escape_string($mybb->input['name']),
"description" => $db->escape_string($mybb->input['description']),
"usetranslation" => $mybb->get_input('usetranslation', MyBB::INPUT_INT),
"enabled" => $mybb->get_input('enabled', MyBB::INPUT_INT),
"disporder" => $mybb->get_input('disporder', MyBB::INPUT_INT)
);
$plugins->run_hooks("admin_config_help_documents_edit_section_commit");
$db->update_query("helpsections", $sql_array, "sid = '{$sid}'");
// Log admin action
log_admin_action($sid, $mybb->input['name'], 'section');
flash_message($lang->success_help_section_updated, 'success');
admin_redirect('index.php?module=config-help_documents');
}
}
$page->add_breadcrumb_item($lang->edit_section);
$page->output_header($lang->help_documents." - ".$lang->edit_section);
$sub_tabs['edit_help_section'] = array(
'title' => $lang->edit_section,
'link' => "index.php?module=config-help_documents&amp;action=edit&amp;sid=".$section['sid'],
'description' => $lang->edit_section_desc
);
$page->output_nav_tabs($sub_tabs, 'edit_help_section');
if($errors)
{
$page->output_inline_error($errors);
}
else
{
$mybb->input['sid'] = $section['sid'];
$mybb->input['name'] = $section['name'];
$mybb->input['description'] = $section['description'];
$mybb->input['disporder'] = $section['disporder'];
$mybb->input['enabled'] = $section['enabled'];
$mybb->input['usetranslation'] = $section['usetranslation'];
}
$form = new Form("index.php?module=config-help_documents&amp;action=edit", "post", "edit");
echo $form->generate_hidden_field("sid", $section['sid']);
echo $form->generate_hidden_field("usetranslation", $mybb->input['usetranslation']);
$form_container = new FormContainer($lang->edit_section." ({$lang->id} ".$section['sid'].")");
$form_container->output_row($lang->title." <em>*</em>", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name');
$form_container->output_row($lang->short_description." <em>*</em>", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description');
$form_container->output_row($lang->display_order, "", $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder', 'min' => 0)), 'disporder');
$form_container->output_row($lang->enabled." <em>*</em>", "", $form->generate_yes_no_radio('enabled', $mybb->input['enabled']));
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->edit_section);
$form->output_submit_wrapper($buttons);
$form->end();
}
// Edit document
else
{
$plugins->run_hooks("admin_config_help_documents_edit_page");
// Do edit?
if($mybb->request_method == "post")
{
$hid = $mybb->get_input('hid', MyBB::INPUT_INT);
if(empty($hid))
{
$errors[] = $lang->error_invalid_sid;
}
if(empty($mybb->input['name']))
{
$errors[] = $lang->error_document_missing_name;
}
if(empty($mybb->input['description']))
{
$errors[] = $lang->error_document_missing_description;
}
if(empty($mybb->input['document']))
{
$errors[] = $lang->error_document_missing_document;
}
if(!isset($mybb->input['enabled']))
{
$errors[] = $lang->error_document_missing_enabled;
}
if($mybb->input['enabled'] != 1)
{
$mybb->input['enabled'] = 0;
}
if(!is_array($errors))
{
$sql_array = array(
"sid" => $mybb->get_input('sid', MyBB::INPUT_INT),
"name" => $db->escape_string($mybb->input['name']),
"description" => $db->escape_string($mybb->input['description']),
"document" => $db->escape_string($mybb->input['document']),
"usetranslation" => $mybb->get_input('usetranslation', MyBB::INPUT_INT),
"enabled" => $mybb->get_input('enabled', MyBB::INPUT_INT),
"disporder" => $mybb->get_input('disporder', MyBB::INPUT_INT)
);
$plugins->run_hooks("admin_config_help_documents_edit_page_commit");
$db->update_query("helpdocs", $sql_array, "hid = '{$hid}'");
// Log admin action
log_admin_action($hid, $mybb->input['name'], 'document');
flash_message($lang->success_help_document_updated, 'success');
admin_redirect('index.php?module=config-help_documents');
}
}
$page->add_breadcrumb_item($lang->edit_document);
$page->output_header($lang->help_documents." - ".$lang->edit_document);
$sub_tabs['edit_help_document'] = array(
'title' => $lang->edit_document,
'link' => "index.php?module=config-help_documents&amp;action=edit&amp;hid=".$hid,
'description' => $lang->edit_document_desc
);
$page->output_nav_tabs($sub_tabs, 'edit_help_document');
if($errors)
{
$page->output_inline_error($errors);
}
else
{
$query = $db->simple_select("helpdocs", "*", "hid = '".$mybb->get_input('hid', MyBB::INPUT_INT)."'");
$doc = $db->fetch_array($query);
$mybb->input['hid'] = $doc['hid'];
$mybb->input['sid'] = $doc['sid'];
$mybb->input['name'] = $doc['name'];
$mybb->input['description'] = $doc['description'];
$mybb->input['document'] = $doc['document'];
$mybb->input['disporder'] = $doc['disporder'];
$mybb->input['enabled'] = $doc['enabled'];
$mybb->input['usetranslation'] = $doc['usetranslation'];
}
$form = new Form("index.php?module=config-help_documents&amp;action=edit", "post", "edit");
echo $form->generate_hidden_field("hid", $doc['hid']);
echo $form->generate_hidden_field("usetranslation", $mybb->input['usetranslation']);
$form_container = new FormContainer($lang->edit_document." ({$lang->id} ".$doc['hid'].")");
$sections = array();
$query = $db->simple_select("helpsections", "sid, name");
while($section = $db->fetch_array($query))
{
$sections[$section['sid']] = $section['name'];
}
$form_container->output_row($lang->section." <em>*</em>", "", $form->generate_select_box("sid", $sections, $mybb->input['sid']), 'sid');
$form_container->output_row($lang->title." <em>*</em>", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name');
$form_container->output_row($lang->short_description." <em>*</em>", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description');
$form_container->output_row($lang->document." <em>*</em>", "", $form->generate_text_area('document', $mybb->input['document'], array('id' => 'document')), 'document');
$form_container->output_row($lang->display_order, "", $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder', 'min' => 0)), 'disporder');
$form_container->output_row($lang->enabled." <em>*</em>", "", $form->generate_yes_no_radio('enabled', $mybb->input['enabled']));
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->edit_document);
$form->output_submit_wrapper($buttons);
$form->end();
}
$page->output_footer();
}
// Delete something
if($mybb->input['action'] == "delete")
{
// User clicked no
if($mybb->input['no'])
{
admin_redirect("index.php?module=config-help_documents");
}
$plugins->run_hooks("admin_config_help_documents_delete");
// Do delete something?
if($mybb->request_method == "post")
{
// Delete section
if(isset($mybb->input['sid']))
{
$sid = $mybb->get_input('sid', MyBB::INPUT_INT);
$query = $db->simple_select("helpsections", "*", "sid='{$sid}'");
$section = $db->fetch_array($query);
// Invalid section?
if(!$section['sid'])
{
flash_message($lang->error_missing_section_id, 'error');
admin_redirect("index.php?module=config-help_documents");
}
// Delete section and its documents
$db->delete_query("helpsections", "sid = '{$section['sid']}'", 1);
$db->delete_query("helpdocs", "sid = '{$section['sid']}'");
$plugins->run_hooks("admin_config_help_documents_delete_section_commit");
// Log admin action
log_admin_action($section['sid'], $section['name'], 'section');
flash_message($lang->success_section_deleted, 'success');
admin_redirect("index.php?module=config-help_documents");
}
// Delete document
else
{
$hid = $mybb->get_input('hid', MyBB::INPUT_INT);
$query = $db->simple_select("helpdocs", "*", "hid='{$hid}'");
$doc = $db->fetch_array($query);
// Invalid document?
if(!$doc['hid'])
{
flash_message($lang->error_missing_hid, 'error');
admin_redirect("index.php?module=config-help_documents");
}
$db->delete_query("helpdocs", "hid = '{$doc['hid']}'", 1);
$plugins->run_hooks("admin_config_help_documents_delete_page_commit");
// Log admin action
log_admin_action($doc['hid'], $doc['name'], 'document');
flash_message($lang->success_document_deleted, 'success');
admin_redirect("index.php?module=config-help_documents");
}
}
// Show form for deletion
else
{
// Section
if(isset($mybb->input['sid']))
{
$sid = $mybb->get_input('sid', MyBB::INPUT_INT);
$page->output_confirm_action("index.php?module=config-help_documents&amp;action=delete&amp;sid={$sid}", $lang->confirm_section_deletion);
}
// Document
else
{
$hid = $mybb->get_input('hid', MyBB::INPUT_INT);
$page->output_confirm_action("index.php?module=config-help_documents&amp;action=delete&amp;hid={$hid}", $lang->confirm_document_deletion);
}
}
}
// List document and sections
if(!$mybb->input['action'])
{
$page->output_header($lang->help_documents);
$sub_tabs['manage_help_documents'] = array(
'title' => $lang->manage_help_documents,
'link' => "index.php?module=config-help_documents",
'description'=> $lang->manage_help_documents_desc
);
$sub_tabs['add_help_document'] = array(
'title' => $lang->add_new_document,
'link' => "index.php?module=config-help_documents&amp;action=add&amp;type=document"
);
$sub_tabs['add_help_section'] = array(
'title' => $lang->add_new_section,
'link' => "index.php?module=config-help_documents&amp;action=add&amp;type=section"
);
$plugins->run_hooks("admin_config_help_documents_start");
$page->output_nav_tabs($sub_tabs, 'manage_help_documents');
$table = new Table;
$table->construct_header($lang->section_document);
$table->construct_header($lang->controls, array('class' => "align_center", 'colspan' => 2, "width" => "150"));
$query = $db->simple_select("helpsections", "*", "", array('order_by' => "disporder"));
while($section = $db->fetch_array($query))
{
$table->construct_cell("<div><strong><a href=\"index.php?module=config-help_documents&amp;action=edit&amp;sid={$section['sid']}\">{$section['name']}</a></strong><br /><small>{$section['description']}</small></div>");
$table->construct_cell("<a href=\"index.php?module=config-help_documents&amp;action=edit&amp;sid={$section['sid']}\">{$lang->edit}</a>", array("class" => "align_center", "width" => '60'));
$table->construct_cell("<a href=\"index.php?module=config-help_documents&amp;action=delete&amp;sid={$section['sid']}&amp;my_post_key={$mybb->post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_section_deletion}')\">{$lang->delete}</a>", array("class" => "align_center", "width" => '90'));
$table->construct_row();
$query2 = $db->simple_select("helpdocs", "*", "sid='{$section['sid']}'", array('order_by' => "disporder"));
while($doc = $db->fetch_array($query2))
{
$table->construct_cell("<div style=\"padding-left: 40px;\"><div><strong><a href=\"index.php?module=config-help_documents&amp;action=edit&amp;hid={$doc['hid']}\">{$doc['name']}</a></strong><br /><small>{$doc['description']}</small></div></div>");
$table->construct_cell("<a href=\"index.php?module=config-help_documents&amp;action=edit&amp;hid={$doc['hid']}\">{$lang->edit}</a>", array("class" => "align_center", "width" => '60'));
$table->construct_cell("<a href=\"index.php?module=config-help_documents&amp;action=delete&amp;hid={$doc['hid']}&amp;my_post_key={$mybb->post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_document_deletion}')\">{$lang->delete}</a>", array("class" => "align_center", "width" => '90'));
$table->construct_row();
}
}
// No documents message
if($table->num_rows() == 0)
{
$table->construct_cell($lang->no_help_documents, array('colspan' => 3));
$table->construct_row();
}
$table->output($lang->help_documents);
$page->output_footer();
}

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title></title>
</head>
<body>
&nbsp;
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,128 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
// Disallow direct access to this file for security reasons
if(!defined("IN_MYBB"))
{
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
}
/**
* @return bool true
*/
function config_meta()
{
global $page, $lang, $plugins;
$sub_menu = array();
$sub_menu['10'] = array("id" => "settings", "title" => $lang->bbsettings, "link" => "index.php?module=config-settings");
$sub_menu['20'] = array("id" => "banning", "title" => $lang->banning, "link" => "index.php?module=config-banning");
$sub_menu['30'] = array("id" => "profile_fields", "title" => $lang->custom_profile_fields, "link" => "index.php?module=config-profile_fields");
$sub_menu['40'] = array("id" => "smilies", "title" => $lang->smilies, "link" => "index.php?module=config-smilies");
$sub_menu['50'] = array("id" => "badwords", "title" => $lang->word_filters, "link" => "index.php?module=config-badwords");
$sub_menu['60'] = array("id" => "mycode", "title" => $lang->mycode, "link" => "index.php?module=config-mycode");
$sub_menu['70'] = array("id" => "languages", "title" => $lang->languages, "link" => "index.php?module=config-languages");
$sub_menu['80'] = array("id" => "post_icons", "title" => $lang->post_icons, "link" => "index.php?module=config-post_icons");
$sub_menu['90'] = array("id" => "help_documents", "title" => $lang->help_documents, "link" => "index.php?module=config-help_documents");
$sub_menu['100'] = array("id" => "plugins", "title" => $lang->plugins, "link" => "index.php?module=config-plugins");
$sub_menu['110'] = array("id" => "attachment_types", "title" => $lang->attachment_types, "link" => "index.php?module=config-attachment_types");
$sub_menu['120'] = array("id" => "mod_tools", "title" => $lang->moderator_tools, "link" => "index.php?module=config-mod_tools");
$sub_menu['130'] = array("id" => "spiders", "title" => $lang->spiders_bots, "link" => "index.php?module=config-spiders");
$sub_menu['140'] = array("id" => "calendars", "title" => $lang->calendars, "link" => "index.php?module=config-calendars");
$sub_menu['150'] = array("id" => "warning", "title" => $lang->warning_system, "link" => "index.php?module=config-warning");
$sub_menu['160'] = array("id" => "thread_prefixes", "title" => $lang->thread_prefixes, "link" => "index.php?module=config-thread_prefixes");
$sub_menu['170'] = array("id" => "questions", "title" => $lang->security_questions, "link" => "index.php?module=config-questions");
$sub_menu['180'] = array("id" => "report_reasons", "title" => $lang->report_reasons, "link" => "index.php?module=config-report_reasons");
$sub_menu = $plugins->run_hooks("admin_config_menu", $sub_menu);
$page->add_menu_item($lang->configuration, "config", "index.php?module=config", 10, $sub_menu);
return true;
}
/**
* @param string $action
*
* @return string
*/
function config_action_handler($action)
{
global $page, $plugins;
$page->active_module = "config";
$actions = array(
'plugins' => array('active' => 'plugins', 'file' => 'plugins.php'),
'smilies' => array('active' => 'smilies', 'file' => 'smilies.php'),
'banning' => array('active' => 'banning', 'file' => 'banning.php'),
'badwords' => array('active' => 'badwords', 'file' => 'badwords.php'),
'profile_fields' => array('active' => 'profile_fields', 'file' => 'profile_fields.php'),
'spiders' => array('active' => 'spiders', 'file' => 'spiders.php'),
'attachment_types' => array('active' => 'attachment_types', 'file' => 'attachment_types.php'),
'languages' => array('active' => 'languages', 'file' => 'languages.php'),
'post_icons' => array('active' => 'post_icons', 'file' => 'post_icons.php'),
'help_documents' => array('active' => 'help_documents', 'file' => 'help_documents.php'),
'calendars' => array('active' => 'calendars', 'file' => 'calendars.php'),
'warning' => array('active' => 'warning', 'file' => 'warning.php'),
'mod_tools' => array('active' => 'mod_tools', 'file' => 'mod_tools.php'),
'mycode' => array('active' => 'mycode', 'file' => 'mycode.php'),
'settings' => array('active' => 'settings', 'file' => 'settings.php'),
'thread_prefixes' => array('active' => 'thread_prefixes', 'file' => 'thread_prefixes.php'),
'questions' => array('active' => 'questions', 'file' => 'questions.php'),
'report_reasons' => array('active' => 'report_reasons', 'file' => 'report_reasons.php')
);
$actions = $plugins->run_hooks("admin_config_action_handler", $actions);
if(isset($actions[$action]))
{
$page->active_action = $actions[$action]['active'];
return $actions[$action]['file'];
}
else
{
$page->active_action = "settings";
return "settings.php";
}
}
/**
* @return array
*/
function config_admin_permissions()
{
global $lang, $plugins;
$admin_permissions = array(
"settings" => $lang->can_manage_settings,
"banning" => $lang->can_manage_banned_accounts,
"profile_fields" => $lang->can_manage_custom_profile_fields,
"smilies" => $lang->can_manage_smilies,
"badwords" => $lang->can_manage_bad_words,
"mycode" => $lang->can_manage_custom_mycode,
"languages" => $lang->can_manage_language_packs,
"post_icons" => $lang->can_manage_post_icons,
"help_documents" => $lang->can_manage_help_documents,
"plugins" => $lang->can_manage_plugins,
"attachment_types" => $lang->can_manage_attachment_types,
"spiders" => $lang->can_manage_spiders_bots,
"calendars" => $lang->can_manage_calendars,
"warning" => $lang->can_manage_warning_system,
"mod_tools" => $lang->can_manage_mod_tools,
"thread_prefixes" => $lang->can_manage_thread_prefixes,
"questions" => $lang->can_manage_security_questions,
"report_reasons" => $lang->can_manage_report_reasons
);
$admin_permissions = $plugins->run_hooks("admin_config_permissions", $admin_permissions);
return array("name" => $lang->configuration, "permissions" => $admin_permissions, "disporder" => 10);
}

View File

@@ -0,0 +1,488 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
// Disallow direct access to this file for security reasons
if(!defined("IN_MYBB"))
{
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
}
$page->add_breadcrumb_item($lang->mycode, "index.php?module=config-mycode");
$plugins->run_hooks("admin_config_mycode_begin");
if($mybb->input['action'] == "toggle_status")
{
if(!verify_post_check($mybb->input['my_post_key']))
{
flash_message($lang->invalid_post_verify_key2, 'error');
admin_redirect("index.php?module=config-mycode");
}
$query = $db->simple_select("mycode", "*", "cid='".$mybb->get_input('cid', MyBB::INPUT_INT)."'");
$mycode = $db->fetch_array($query);
if(!$mycode['cid'])
{
flash_message($lang->error_invalid_mycode, 'error');
admin_redirect("index.php?module=config-mycode");
}
$plugins->run_hooks("admin_config_mycode_toggle_status");
if($mycode['active'] == 1)
{
$new_status = 0;
$phrase = $lang->success_deactivated_mycode;
}
else
{
$new_status = 1;
$phrase = $lang->success_activated_mycode;
}
$mycode_update = array(
'active' => $new_status,
);
$plugins->run_hooks("admin_config_mycode_toggle_status_commit");
$db->update_query("mycode", $mycode_update, "cid='{$mycode['cid']}'");
$cache->update_mycode();
// Log admin action
log_admin_action($mycode['cid'], $mycode['title'], $new_status);
flash_message($phrase, 'success');
admin_redirect('index.php?module=config-mycode');
}
if($mybb->input['action'] == "xmlhttp_test_mycode" && $mybb->request_method == "post")
{
$plugins->run_hooks("admin_config_mycode_xmlhttp_test_mycode_start");
// Send no cache headers
header("Expires: Sat, 1 Jan 2000 01:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
header("Content-type: text/html");
$sandbox = test_regex($mybb->input['regex'], $mybb->input['replacement'], $mybb->input['test_value']);
$plugins->run_hooks("admin_config_mycode_xmlhttp_test_mycode_end");
echo $sandbox['actual'];
exit;
}
if($mybb->input['action'] == "add")
{
$plugins->run_hooks("admin_config_mycode_add");
if($mybb->request_method == "post")
{
if(!trim($mybb->input['title']))
{
$errors[] = $lang->error_missing_title;
}
if(!trim($mybb->input['regex']))
{
$errors[] = $lang->error_missing_regex;
}
$regex = str_replace("\x0", "", $mybb->input['regex']);
if(check_existing_regex($regex))
{
$errors[] = $lang->error_regex_already_available;
}
if(!trim($mybb->input['replacement']))
{
$errors[] = $lang->error_missing_replacement;
}
if($mybb->input['test'])
{
$errors[] = $lang->changes_not_saved;
$sandbox = test_regex($mybb->input['regex'], $mybb->input['replacement'], $mybb->input['test_value']);
}
if(!$errors)
{
$new_mycode = array(
'title' => $db->escape_string($mybb->input['title']),
'description' => $db->escape_string($mybb->input['description']),
'regex' => $db->escape_string($regex),
'replacement' => $db->escape_string($mybb->input['replacement']),
'active' => $mybb->get_input('active', MyBB::INPUT_INT),
'parseorder' => $mybb->get_input('parseorder', MyBB::INPUT_INT)
);
$cid = $db->insert_query("mycode", $new_mycode);
$plugins->run_hooks("admin_config_mycode_add_commit");
$cache->update_mycode();
// Log admin action
log_admin_action($cid, $mybb->input['title']);
flash_message($lang->success_added_mycode, 'success');
admin_redirect('index.php?module=config-mycode');
}
}
$sub_tabs['mycode'] = array(
'title' => $lang->mycode,
'link' => "index.php?module=config-mycode",
'description' => $lang->mycode_desc
);
$sub_tabs['add_new_mycode'] = array(
'title' => $lang->add_new_mycode,
'link' => "index.php?module=config-mycode&amp;action=add",
'description' => $lang->add_new_mycode_desc
);
$page->extra_header .= "
<script type=\"text/javascript\">
var my_post_key = '".$mybb->post_code."';
lang.mycode_sandbox_test_error = \"{$lang->mycode_sandbox_test_error}\";
</script>";
$page->add_breadcrumb_item($lang->add_new_mycode);
$page->output_header($lang->custom_mycode." - ".$lang->add_new_mycode);
$page->output_nav_tabs($sub_tabs, 'add_new_mycode');
if($errors)
{
$page->output_inline_error($errors);
}
else
{
$mybb->input['active'] = 1;
}
$form = new Form("index.php?module=config-mycode&amp;action=add", "post", "add");
$form_container = new FormContainer($lang->add_mycode);
$form_container->output_row($lang->title." <em>*</em>", '', $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title');
$form_container->output_row($lang->short_description, '', $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description');
$form_container->output_row($lang->regular_expression." <em>*</em>", $lang->regular_expression_desc.'<br /><strong>'.$lang->example.'</strong> \[b\](.*?)\[/b\]', $form->generate_text_area('regex', $mybb->input['regex'], array('id' => 'regex')), 'regex');
$form_container->output_row($lang->replacement." <em>*</em>", $lang->replacement_desc.'<br /><strong>'.$lang->example.'</strong> &lt;strong&gt;$1&lt;/strong&gt;', $form->generate_text_area('replacement', $mybb->input['replacement'], array('id' => 'replacement')), 'replacement');
$form_container->output_row($lang->enabled." <em>*</em>", '', $form->generate_yes_no_radio('active', $mybb->input['active']));
$form_container->output_row($lang->parse_order, $lang->parse_order_desc, $form->generate_numeric_field('parseorder', $mybb->input['parseorder'], array('id' => 'parseorder', 'min' => 0)), 'parseorder');
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_mycode);
$form->output_submit_wrapper($buttons);
// Sandbox
echo "<br />\n";
$form_container = new FormContainer($lang->sandbox);
$form_container->output_row($lang->sandbox_desc);
$form_container->output_row($lang->test_value, $lang->test_value_desc, $form->generate_text_area('test_value', $mybb->input['test_value'], array('id' => 'test_value'))."<br />".$form->generate_submit_button($lang->test, array('id' => 'test', 'name' => 'test')), 'test_value');
$form_container->output_row($lang->result_html, $lang->result_html_desc, $form->generate_text_area('result_html', $sandbox['html'], array('id' => 'result_html', 'disabled' => 1)), 'result_html');
$form_container->output_row($lang->result_actual, $lang->result_actual_desc, "<div id=\"result_actual\">{$sandbox['actual']}</div>");
$form_container->end();
echo '<script type="text/javascript" src="./jscripts/mycode_sandbox.js"></script>';
echo '<script type="text/javascript">
//<![CDATA[
$(function(){
new MyCodeSandbox("./index.php?module=config-mycode&action=xmlhttp_test_mycode", $("#test"), $("#regex"), $("#replacement"), $("#test_value"), $("#result_html"), $("#result_actual"));
});
//]]>
</script>';
$form->end();
$page->output_footer();
}
if($mybb->input['action'] == "edit")
{
$query = $db->simple_select("mycode", "*", "cid='".$mybb->get_input('cid', MyBB::INPUT_INT)."'");
$mycode = $db->fetch_array($query);
if(!$mycode['cid'])
{
flash_message($lang->error_invalid_mycode, 'error');
admin_redirect("index.php?module=config-mycode");
}
$plugins->run_hooks("admin_config_mycode_edit");
if($mybb->request_method == "post")
{
if(!trim($mybb->input['title']))
{
$errors[] = $lang->error_missing_title;
}
if(!trim($mybb->input['regex']))
{
$errors[] = $lang->error_missing_regex;
}
$regex = str_replace("\x0", "", $mybb->input['regex']);
if(check_existing_regex($regex, $mycode))
{
$errors[] = $lang->error_regex_already_available;
}
if(!trim($mybb->input['replacement']))
{
$errors[] = $lang->error_missing_replacement;
}
if($mybb->input['test'])
{
$errors[] = $lang->changes_not_saved;
$sandbox = test_regex($mybb->input['regex'], $mybb->input['replacement'], $mybb->input['test_value']);
}
if(!$errors)
{
$updated_mycode = array(
'title' => $db->escape_string($mybb->input['title']),
'description' => $db->escape_string($mybb->input['description']),
'regex' => $db->escape_string($regex),
'replacement' => $db->escape_string($mybb->input['replacement']),
'active' => $mybb->get_input('active', MyBB::INPUT_INT),
'parseorder' => $mybb->get_input('parseorder', MyBB::INPUT_INT)
);
$plugins->run_hooks("admin_config_mycode_edit_commit");
$db->update_query("mycode", $updated_mycode, "cid='{$mycode['cid']}'");
$cache->update_mycode();
// Log admin action
log_admin_action($mycode['cid'], $mybb->input['title']);
flash_message($lang->success_updated_mycode, 'success');
admin_redirect('index.php?module=config-mycode');
}
}
$sub_tabs['edit_mycode'] = array(
'title' => $lang->edit_mycode,
'link' => "index.php?module=config-mycode&amp;action=edit",
'description' => $lang->edit_mycode_desc
);
$page->extra_header .= "
<script type=\"text/javascript\">
var my_post_key = '".$mybb->post_code."';
lang.mycode_sandbox_test_error = \"{$lang->mycode_sandbox_test_error}\";
</script>";
$page->add_breadcrumb_item($lang->edit_mycode);
$page->output_header($lang->custom_mycode." - ".$lang->edit_mycode);
$page->output_nav_tabs($sub_tabs, 'edit_mycode');
$form = new Form("index.php?module=config-mycode&amp;action=edit", "post", "edit");
echo $form->generate_hidden_field('cid', $mycode['cid']);
if($errors)
{
$page->output_inline_error($errors);
}
else
{
$mybb->input = array_merge($mybb->input, $mycode);
}
$form_container = new FormContainer($lang->edit_mycode);
$form_container->output_row($lang->title." <em>*</em>", '', $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title');
$form_container->output_row($lang->short_description, '', $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description');
$form_container->output_row($lang->regular_expression." <em>*</em>", $lang->regular_expression_desc.'<br /><strong>'.$lang->example.'</strong> \[b\](.*?)\[/b\]', $form->generate_text_area('regex', $mybb->input['regex'], array('id' => 'regex')), 'regex');
$form_container->output_row($lang->replacement." <em>*</em>", $lang->replacement_desc.'<br /><strong>'.$lang->example.'</strong> &lt;strong&gt;$1&lt;/strong&gt;', $form->generate_text_area('replacement', $mybb->input['replacement'], array('id' => 'replacement')), 'replacement');
$form_container->output_row($lang->enabled." <em>*</em>", '', $form->generate_yes_no_radio('active', $mybb->input['active']));
$form_container->output_row($lang->parse_order, $lang->parse_order_desc, $form->generate_numeric_field('parseorder', $mybb->input['parseorder'], array('id' => 'parseorder', 'min' => 0)), 'parseorder');
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_mycode);
$form->output_submit_wrapper($buttons);
// Sandbox
echo "<br />\n";
$form_container = new FormContainer($lang->sandbox);
$form_container->output_row($lang->sandbox_desc);
$form_container->output_row($lang->test_value, $lang->test_value_desc, $form->generate_text_area('test_value', $mybb->input['test_value'], array('id' => 'test_value'))."<br />".$form->generate_submit_button($lang->test, array('id' => 'test', 'name' => 'test')), 'test_value');
$form_container->output_row($lang->result_html, $lang->result_html_desc, $form->generate_text_area('result_html', $sandbox['html'], array('id' => 'result_html', 'disabled' => 1)), 'result_html');
$form_container->output_row($lang->result_actual, $lang->result_actual_desc, "<div id=\"result_actual\">{$sandbox['actual']}</div>");
$form_container->end();
echo '<script type="text/javascript" src="./jscripts/mycode_sandbox.js"></script>';
echo '<script type="text/javascript">
$(function(){
//<![CDATA[
new MyCodeSandbox("./index.php?module=config-mycode&action=xmlhttp_test_mycode", $("#test"), $("#regex"), $("#replacement"), $("#test_value"), $("#result_html"), $("#result_actual"));
});
//]]>
</script>';
$form->end();
$page->output_footer();
}
if($mybb->input['action'] == "delete")
{
$query = $db->simple_select("mycode", "*", "cid='".$mybb->get_input('cid', MyBB::INPUT_INT)."'");
$mycode = $db->fetch_array($query);
if(!$mycode['cid'])
{
flash_message($lang->error_invalid_mycode, 'error');
admin_redirect("index.php?module=config-mycode");
}
$plugins->run_hooks("admin_config_mycode_delete");
// User clicked no
if($mybb->input['no'])
{
admin_redirect("index.php?module=config-mycode");
}
if($mybb->request_method == "post")
{
$db->delete_query("mycode", "cid='{$mycode['cid']}'");
$plugins->run_hooks("admin_config_mycode_delete_commit");
$cache->update_mycode();
// Log admin action
log_admin_action($mycode['cid'], $mycode['title']);
flash_message($lang->success_deleted_mycode, 'success');
admin_redirect("index.php?module=config-mycode");
}
else
{
$page->output_confirm_action("index.php?module=config-mycode&amp;action=delete&amp;cid={$mycode['cid']}", $lang->confirm_mycode_deletion);
}
}
if(!$mybb->input['action'])
{
$plugins->run_hooks("admin_config_mycode_start");
$page->output_header($lang->custom_mycode);
$sub_tabs['mycode'] = array(
'title' => $lang->mycode,
'link' => "index.php?module=config-mycode",
'description' => $lang->mycode_desc
);
$sub_tabs['add_new_mycode'] = array(
'title' => $lang->add_new_mycode,
'link' => "index.php?module=config-mycode&amp;action=add"
);
$page->output_nav_tabs($sub_tabs, 'mycode');
$table = new Table;
$table->construct_header($lang->title);
$table->construct_header($lang->controls, array('class' => 'align_center', 'width' => 150));
$query = $db->simple_select("mycode", "*", "", array('order_by' => 'parseorder'));
while($mycode = $db->fetch_array($query))
{
if($mycode['active'] == 1)
{
$phrase = $lang->deactivate_mycode;
$icon = "<img src=\"styles/{$page->style}/images/icons/bullet_on.png\" alt=\"({$lang->alt_enabled})\" title=\"{$lang->alt_enabled}\" style=\"vertical-align: middle;\" /> ";
}
else
{
$phrase = $lang->activate_mycode;
$icon = "<img src=\"styles/{$page->style}/images/icons/bullet_off.png\" alt=\"({$lang->alt_disabled})\" title=\"{$lang->alt_disabled}\" style=\"vertical-align: middle;\" /> ";
}
if($mycode['description'])
{
$mycode['description'] = "<small>".htmlspecialchars_uni($mycode['description'])."</small>";
}
$table->construct_cell("<div>{$icon}<strong><a href=\"index.php?module=config-mycode&amp;action=edit&amp;cid={$mycode['cid']}\">".htmlspecialchars_uni($mycode['title'])."</a></strong><br />{$mycode['description']}</div>");
$popup = new PopupMenu("mycode_{$mycode['cid']}", $lang->options);
$popup->add_item($lang->edit_mycode, "index.php?module=config-mycode&amp;action=edit&amp;cid={$mycode['cid']}");
$popup->add_item($phrase, "index.php?module=config-mycode&amp;action=toggle_status&amp;cid={$mycode['cid']}&amp;my_post_key={$mybb->post_code}");
$popup->add_item($lang->delete_mycode, "index.php?module=config-mycode&amp;action=delete&amp;cid={$mycode['cid']}&amp;my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_mycode_deletion}')");
$table->construct_cell($popup->fetch(), array('class' => 'align_center'));
$table->construct_row();
}
if($table->num_rows() == 0)
{
$table->construct_cell($lang->no_mycode, array('colspan' => 2));
$table->construct_row();
}
$table->output($lang->custom_mycode);
$page->output_footer();
}
/**
* @param string $regex
* @param string $replacement
* @param string $test
*
* @return array
*/
function test_regex($regex, $replacement, $test)
{
$array = array();
$array['actual'] = @preg_replace("#".str_replace("\x0", "", $regex)."#si", $replacement, $test);
$array['html'] = htmlspecialchars_uni($array['actual']);
return $array;
}
/**
* Checks if a regex is already available
*
* @param string $regex The regex to check
* @param array $current The currently edited MyCode
*
* @return bool True if already available, false otherwise
*/
function check_existing_regex($regex='', $current=array())
{
global $cache;
if(!empty($current) && $current['regex'] == $regex)
{
return false;
}
$mycodes = $cache->read('mycode');
foreach($mycodes as $mycode)
{
if($mycode['regex'] == $regex)
{
return true;
}
}
return false;
}

View File

@@ -0,0 +1,715 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
// Disallow direct access to this file for security reasons
if(!defined("IN_MYBB"))
{
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
}
$page->add_breadcrumb_item($lang->plugins, "index.php?module=config-plugins");
$plugins->run_hooks("admin_config_plugins_begin");
if($mybb->input['action'] == "browse")
{
$page->add_breadcrumb_item($lang->browse_plugins);
$page->output_header($lang->browse_plugins);
$sub_tabs['plugins'] = array(
'title' => $lang->plugins,
'link' => "index.php?module=config-plugins",
'description' => $lang->plugins_desc
);
$sub_tabs['update_plugins'] = array(
'title' => $lang->plugin_updates,
'link' => "index.php?module=config-plugins&amp;action=check",
'description' => $lang->plugin_updates_desc
);
$sub_tabs['browse_plugins'] = array(
'title' => $lang->browse_plugins,
'link' => "index.php?module=config-plugins&amp;action=browse",
'description' => $lang->browse_plugins_desc
);
$page->output_nav_tabs($sub_tabs, 'browse_plugins');
// Process search requests
require_once MYBB_ROOT."inc/class_xml.php";
$keywords = "";
if($mybb->input['keywords'])
{
$keywords = "&keywords=".urlencode($mybb->input['keywords']);
}
if($mybb->input['page'])
{
$url_page = "&page=".$mybb->get_input('page', MyBB::INPUT_INT);
}
else
{
$mybb->input['page'] = 1;
$url_page = "";
}
// Gets the major version code. i.e. 1410 -> 1400 or 121 -> 1200
$major_version_code = round($mybb->version_code/100, 0)*100;
// Convert to mods site version codes
$search_version = ($major_version_code/100).'x';
$contents = fetch_remote_file("https://community.mybb.com/xmlbrowse.php?type=plugins&version={$search_version}{$keywords}{$url_page}", $post_data);
if(!$contents)
{
$page->output_inline_error($lang->error_communication_problem);
$page->output_footer();
exit;
}
$table = new Table;
$table->construct_header($lang->plugin);
$table->construct_header($lang->latest_version, array("class" => "align_center", 'width' => 125));
$table->construct_header($lang->controls, array("class" => "align_center", 'width' => 125));
$parser = new XMLParser($contents);
$tree = $parser->get_tree();
if(!is_array($tree) || !isset($tree['results']))
{
$page->output_inline_error($lang->error_communication_problem);
$page->output_footer();
exit;
}
if(!empty($tree['results']['result']))
{
if(array_key_exists("tag", $tree['results']['result']))
{
$only_plugin = $tree['results']['result'];
unset($tree['results']['result']);
$tree['results']['result'][0] = $only_plugin;
}
require_once MYBB_ROOT . '/inc/class_parser.php';
$post_parser = new postParser();
foreach($tree['results']['result'] as $result)
{
$result['name']['value'] = htmlspecialchars_uni($result['name']['value']);
$result['description']['value'] = htmlspecialchars_uni($result['description']['value']);
$result['author']['value'] = $post_parser->parse_message($result['author']['value'], array(
'allow_html' => true
)
);
$result['version']['value'] = htmlspecialchars_uni($result['version']['value']);
$result['download_url']['value'] = htmlspecialchars_uni(html_entity_decode($result['download_url']['value']));
$table->construct_cell("<strong>{$result['name']['value']}</strong><br /><small>{$result['description']['value']}</small><br /><i><small>{$lang->created_by} {$result['author']['value']}</small></i>");
$table->construct_cell($result['version']['value'], array("class" => "align_center"));
$table->construct_cell("<strong><a href=\"https://community.mybb.com/{$result['download_url']['value']}\" target=\"_blank\" rel=\"noopener\">{$lang->download}</a></strong>", array("class" => "align_center"));
$table->construct_row();
}
}
if($table->num_rows() == 0)
{
$table->construct_cell($lang->error_no_results_found, array("colspan" => 3));
$table->construct_row();
}
$search = new Form("index.php?module=config-plugins&amp;action=browse", 'post', 'search_form');
echo "<div style=\"padding-bottom: 3px; margin-top: -9px; text-align: right;\">";
if($mybb->input['keywords'])
{
$default_class = '';
$value = htmlspecialchars_uni($mybb->input['keywords']);
}
else
{
$default_class = "search_default";
$value = $lang->search_for_plugins;
}
echo $search->generate_text_box('keywords', $value, array('id' => 'search_keywords', 'class' => "{$default_class} field150 field_small"))."\n";
echo "<input type=\"submit\" class=\"search_button\" value=\"{$lang->search}\" />\n";
echo "<script type=\"text/javascript\">
var form = $(\"#search_form\");
form.on('submit', function()
{
var search = $(\"#search_keywords\");
if(search.val() == '' || search.val() == '{$lang->search_for_plugins}')
{
search.trigger('focus');
return false;
}
});
var search = $(\"#search_keywords\");
search.on('focus', function()
{
var searched_focus = $(this);
if(searched_focus.val() == '{$lang->search_for_plugins}')
{
searched_focus.removeClass(\"search_default\");
searched_focus.val(\"\");
}
}).on('blur', function()
{
var searched_blur = $(this);
if(searched_blur.val() == \"\")
{
searched_blur.addClass('search_default');
searched_blur.val('{$lang->search_for_plugins}');
}
});
// fix the styling used if we have a different default value
if(search.val() != '{$lang->search_for_plugins}')
{
search.removeClass('search_default');
}
</script>\n";
echo "</div>\n";
echo $search->end();
// Recommended plugins = Default; Otherwise search results & pagination
if($mybb->request_method == "post")
{
$table->output("<span style=\"float: right;\"><small><a href=\"https://community.mybb.com/mods.php?action=browse&category=plugins\" target=\"_blank\" rel=\"noopener\">{$lang->browse_all_plugins}</a></small></span>".$lang->sprintf($lang->browse_results_for_mybb, $mybb->version));
}
else
{
$table->output("<span style=\"float: right;\"><small><a href=\"https://community.mybb.com/mods.php?action=browse&category=plugins\" target=\"_blank\" rel=\"noopener\">{$lang->browse_all_plugins}</a></small></span>".$lang->sprintf($lang->recommended_plugins_for_mybb, $mybb->version));
}
echo "<br />".draw_admin_pagination($mybb->input['page'], 15, $tree['results']['attributes']['total'], "index.php?module=config-plugins&amp;action=browse{$keywords}&amp;page={page}");
$page->output_footer();
}
if($mybb->input['action'] == "check")
{
$plugins_list = get_plugins_list();
$plugins->run_hooks("admin_config_plugins_check");
$info = array();
if($plugins_list)
{
$active_hooks = $plugins->hooks;
foreach($plugins_list as $plugin_file)
{
require_once MYBB_ROOT."inc/plugins/".$plugin_file;
$codename = str_replace(".php", "", $plugin_file);
$infofunc = $codename."_info";
if(!function_exists($infofunc))
{
continue;
}
$plugininfo = $infofunc();
$plugininfo['guid'] = trim($plugininfo['guid']);
$plugininfo['codename'] = trim($plugininfo['codename']);
if($plugininfo['codename'] != "")
{
$info[] = $plugininfo['codename'];
$names[$plugininfo['codename']] = array('name' => $plugininfo['name'], 'version' => $plugininfo['version']);
}
elseif($plugininfo['guid'] != "")
{
$info[] = $plugininfo['guid'];
$names[$plugininfo['guid']] = array('name' => $plugininfo['name'], 'version' => $plugininfo['version']);
}
}
$plugins->hooks = $active_hooks;
}
if(empty($info))
{
flash_message($lang->error_vcheck_no_supported_plugins, 'error');
admin_redirect("index.php?module=config-plugins");
}
$url = "https://community.mybb.com/version_check.php?";
$url .= http_build_query(array("info" => $info))."&";
require_once MYBB_ROOT."inc/class_xml.php";
$contents = fetch_remote_file($url);
if(!$contents)
{
flash_message($lang->error_vcheck_communications_problem, 'error');
admin_redirect("index.php?module=config-plugins");
}
$contents = trim($contents);
$parser = new XMLParser($contents);
$tree = $parser->get_tree();
if(!is_array($tree) || !isset($tree['plugins']))
{
flash_message($lang->error_communication_problem, 'error');
admin_redirect("index.php?module=config-plugins");
}
if(array_key_exists('error', $tree['plugins']))
{
switch($tree['plugins'][0]['error'])
{
case "1":
$error_msg = $lang->error_no_input;
break;
case "2":
$error_msg = $lang->error_no_pids;
break;
default:
$error_msg = "";
}
flash_message($lang->error_communication_problem.$error_msg, 'error');
admin_redirect("index.php?module=config-plugins");
}
$table = new Table;
$table->construct_header($lang->plugin);
$table->construct_header($lang->your_version, array("class" => "align_center", 'width' => 125));
$table->construct_header($lang->latest_version, array("class" => "align_center", 'width' => 125));
$table->construct_header($lang->controls, array("class" => "align_center", 'width' => 125));
if(!is_array($tree['plugins']['plugin']))
{
flash_message($lang->success_plugins_up_to_date, 'success');
admin_redirect("index.php?module=config-plugins");
}
if(array_key_exists("tag", $tree['plugins']['plugin']))
{
$only_plugin = $tree['plugins']['plugin'];
unset($tree['plugins']['plugin']);
$tree['plugins']['plugin'][0] = $only_plugin;
}
foreach($tree['plugins']['plugin'] as $plugin)
{
$compare_by = array_key_exists("codename", $plugin['attributes']) ? "codename" : "guid";
$is_vulnerable = array_key_exists("vulnerable", $plugin) ? true : false;
if(version_compare($names[$plugin['attributes'][$compare_by]]['version'], $plugin['version']['value'], "<"))
{
$plugin['download_url']['value'] = htmlspecialchars_uni($plugin['download_url']['value']);
$plugin['vulnerable']['value'] = htmlspecialchars_uni($plugin['vulnerable']['value']);
$plugin['version']['value'] = htmlspecialchars_uni($plugin['version']['value']);
if($is_vulnerable)
{
$table->construct_cell("<div class=\"error\" id=\"flash_message\">
{$lang->error_vcheck_vulnerable} {$names[$plugin['attributes'][$compare_by]]['name']}
</div>
<p> <b>{$lang->error_vcheck_vulnerable_notes}</b> <br /><br /> {$plugin['vulnerable']['value']}</p>");
}
else
{
$table->construct_cell("<strong>{$names[$plugin['attributes'][$compare_by]]['name']}</strong>");
}
$table->construct_cell("{$names[$plugin['attributes'][$compare_by]]['version']}", array("class" => "align_center"));
$table->construct_cell("<strong><span style=\"color: #C00\">{$plugin['version']['value']}</span></strong>", array("class" => "align_center"));
if($is_vulnerable)
{
$table->construct_cell("<a href=\"index.php?module=config-plugins\"><b>{$lang->deactivate}</b></a>", array("class" => "align_center", "width" => 150));
}
else
{
$table->construct_cell("<strong><a href=\"https://community.mybb.com/{$plugin['download_url']['value']}\" target=\"_blank\" rel=\"noopener\">{$lang->download}</a></strong>", array("class" => "align_center"));
}
$table->construct_row();
}
}
if($table->num_rows() == 0)
{
flash_message($lang->success_plugins_up_to_date, 'success');
admin_redirect("index.php?module=config-plugins");
}
$page->add_breadcrumb_item($lang->plugin_updates);
$page->output_header($lang->plugin_updates);
$sub_tabs['plugins'] = array(
'title' => $lang->plugins,
'link' => "index.php?module=config-plugins",
);
$sub_tabs['update_plugins'] = array(
'title' => $lang->plugin_updates,
'link' => "index.php?module=config-plugins&amp;action=check",
'description' => $lang->plugin_updates_desc
);
$sub_tabs['browse_plugins'] = array(
'title' => $lang->browse_plugins,
'link' => "index.php?module=config-plugins&amp;action=browse",
'description' => $lang->browse_plugins_desc
);
$page->output_nav_tabs($sub_tabs, 'update_plugins');
$table->output($lang->plugin_updates);
$page->output_footer();
}
// Activates or deactivates a specific plugin
if($mybb->input['action'] == "activate" || $mybb->input['action'] == "deactivate")
{
if(!verify_post_check($mybb->input['my_post_key']))
{
flash_message($lang->invalid_post_verify_key2, 'error');
admin_redirect("index.php?module=config-plugins");
}
if($mybb->input['action'] == "activate")
{
$plugins->run_hooks("admin_config_plugins_activate");
}
else
{
$plugins->run_hooks("admin_config_plugins_deactivate");
}
$codename = $mybb->input['plugin'];
$codename = str_replace(array(".", "/", "\\"), "", $codename);
$file = basename($codename.".php");
// Check if the file exists and throw an error if it doesn't
if(!file_exists(MYBB_ROOT."inc/plugins/$file"))
{
flash_message($lang->error_invalid_plugin, 'error');
admin_redirect("index.php?module=config-plugins");
}
$plugins_cache = $cache->read("plugins");
$active_plugins = $plugins_cache['active'];
require_once MYBB_ROOT."inc/plugins/$file";
$installed_func = "{$codename}_is_installed";
$installed = true;
if(function_exists($installed_func) && $installed_func() != true)
{
$installed = false;
}
$install_uninstall = false;
if($mybb->input['action'] == "activate")
{
$message = $lang->success_plugin_activated;
// Plugin is compatible with this version?
if($plugins->is_compatible($codename) == false)
{
flash_message($lang->sprintf($lang->plugin_incompatible, $mybb->version), 'error');
admin_redirect("index.php?module=config-plugins");
}
// If not installed and there is a custom installation function
if($installed == false && function_exists("{$codename}_install"))
{
call_user_func("{$codename}_install");
$message = $lang->success_plugin_installed;
$install_uninstall = true;
}
if(function_exists("{$codename}_activate"))
{
call_user_func("{$codename}_activate");
}
$active_plugins[$codename] = $codename;
$executed[] = 'activate';
}
else if($mybb->input['action'] == "deactivate")
{
$message = $lang->success_plugin_deactivated;
if(function_exists("{$codename}_deactivate"))
{
call_user_func("{$codename}_deactivate");
}
if($mybb->input['uninstall'] == 1 && function_exists("{$codename}_uninstall"))
{
call_user_func("{$codename}_uninstall");
$message = $lang->success_plugin_uninstalled;
$install_uninstall = true;
}
unset($active_plugins[$codename]);
}
// Update plugin cache
$plugins_cache['active'] = $active_plugins;
$cache->update("plugins", $plugins_cache);
// Log admin action
log_admin_action($codename, $install_uninstall);
if($mybb->input['action'] == "activate")
{
$plugins->run_hooks("admin_config_plugins_activate_commit");
}
else
{
$plugins->run_hooks("admin_config_plugins_deactivate_commit");
}
flash_message($message, 'success');
admin_redirect("index.php?module=config-plugins");
}
if(!$mybb->input['action'])
{
$page->output_header($lang->plugins);
$sub_tabs['plugins'] = array(
'title' => $lang->plugins,
'link' => "index.php?module=config-plugins",
'description' => $lang->plugins_desc
);
$sub_tabs['update_plugins'] = array(
'title' => $lang->plugin_updates,
'link' => "index.php?module=config-plugins&amp;action=check",
'description' => $lang->plugin_updates_desc
);
$sub_tabs['browse_plugins'] = array(
'title' => $lang->browse_plugins,
'link' => "index.php?module=config-plugins&amp;action=browse",
'description' => $lang->browse_plugins_desc
);
$page->output_nav_tabs($sub_tabs, 'plugins');
// Let's make things easier for our user - show them active
// and inactive plugins in different lists
$plugins_cache = $cache->read("plugins");
$active_plugins = $plugins_cache['active'];
$plugins_list = get_plugins_list();
$plugins->run_hooks("admin_config_plugins_plugin_list");
if(!empty($plugins_list))
{
$a_plugins = $i_plugins = array();
foreach($plugins_list as $plugin_file)
{
require_once MYBB_ROOT."inc/plugins/".$plugin_file;
$codename = str_replace(".php", "", $plugin_file);
$infofunc = $codename."_info";
if(!function_exists($infofunc))
{
continue;
}
$plugininfo = $infofunc();
$plugininfo['codename'] = $codename;
if($active_plugins[$codename])
{
// This is an active plugin
$plugininfo['is_active'] = 1;
$a_plugins[] = $plugininfo;
continue;
}
// Either installed and not active or completely inactive
$i_plugins[] = $plugininfo;
}
$table = new Table;
$table->construct_header($lang->plugin);
$table->construct_header($lang->controls, array("colspan" => 2, "class" => "align_center", "width" => 300));
if(empty($a_plugins))
{
$table->construct_cell($lang->no_active_plugins, array('colspan' => 3));
$table->construct_row();
}
else
{
build_plugin_list($a_plugins);
}
$table->output($lang->active_plugin);
$table = new Table;
$table->construct_header($lang->plugin);
$table->construct_header($lang->controls, array("colspan" => 2, "class" => "align_center", "width" => 300));
if(empty($i_plugins))
{
$table->construct_cell($lang->no_inactive_plugins, array('colspan' => 3));
$table->construct_row();
}
else
{
build_plugin_list($i_plugins);
}
$table->output($lang->inactive_plugin);
}
else
{
// No plugins
$table = new Table;
$table->construct_header($lang->plugin);
$table->construct_header($lang->controls, array("colspan" => 2, "class" => "align_center", "width" => 300));
$table->construct_cell($lang->no_plugins, array('colspan' => 3));
$table->construct_row();
$table->output($lang->plugins);
}
$page->output_footer();
}
/**
* @return array
*/
function get_plugins_list()
{
// Get a list of the plugin files which exist in the plugins directory
$dir = @opendir(MYBB_ROOT."inc/plugins/");
if($dir)
{
while($file = readdir($dir))
{
$ext = get_extension($file);
if($ext == "php")
{
$plugins_list[] = $file;
}
}
@sort($plugins_list);
}
@closedir($dir);
return $plugins_list;
}
/**
* @param array $plugin_list
*/
function build_plugin_list($plugin_list)
{
global $lang, $mybb, $plugins, $table;
foreach($plugin_list as $plugininfo)
{
if($plugininfo['website'])
{
$plugininfo['name'] = "<a href=\"".$plugininfo['website']."\">".$plugininfo['name']."</a>";
}
if($plugininfo['authorsite'])
{
$plugininfo['author'] = "<a href=\"".$plugininfo['authorsite']."\">".$plugininfo['author']."</a>";
}
if($plugins->is_compatible($plugininfo['codename']) == false)
{
$compatibility_warning = "<span style=\"color: red;\">".$lang->sprintf($lang->plugin_incompatible, $mybb->version)."</span>";
}
else
{
$compatibility_warning = "";
}
$installed_func = "{$plugininfo['codename']}_is_installed";
$install_func = "{$plugininfo['codename']}_install";
$uninstall_func = "{$plugininfo['codename']}_uninstall";
$installed = true;
$install_button = false;
$uninstall_button = false;
if(function_exists($installed_func) && $installed_func() != true)
{
$installed = false;
}
if(function_exists($install_func))
{
$install_button = true;
}
if(function_exists($uninstall_func))
{
$uninstall_button = true;
}
$table->construct_cell("<strong>{$plugininfo['name']}</strong> ({$plugininfo['version']})<br /><small>{$plugininfo['description']}</small><br /><i><small>{$lang->created_by} {$plugininfo['author']}</small></i>");
// Plugin is not installed at all
if($installed == false)
{
if($compatibility_warning)
{
$table->construct_cell("{$compatibility_warning}", array("class" => "align_center", "colspan" => 2));
}
else
{
$table->construct_cell("<a href=\"index.php?module=config-plugins&amp;action=activate&amp;plugin={$plugininfo['codename']}&amp;my_post_key={$mybb->post_code}\">{$lang->install_and_activate}</a>", array("class" => "align_center", "colspan" => 2));
}
}
// Plugin is activated and installed
else if($plugininfo['is_active'])
{
$table->construct_cell("<a href=\"index.php?module=config-plugins&amp;action=deactivate&amp;plugin={$plugininfo['codename']}&amp;my_post_key={$mybb->post_code}\">{$lang->deactivate}</a>", array("class" => "align_center", "width" => 150));
if($uninstall_button)
{
$table->construct_cell("<a href=\"index.php?module=config-plugins&amp;action=deactivate&amp;uninstall=1&amp;plugin={$plugininfo['codename']}&amp;my_post_key={$mybb->post_code}\">{$lang->uninstall}</a>", array("class" => "align_center", "width" => 150));
}
else
{
$table->construct_cell("&nbsp;", array("class" => "align_center", "width" => 150));
}
}
// Plugin is installed but not active
else if($installed == true)
{
if($compatibility_warning && !$uninstall_button)
{
$table->construct_cell("{$compatibility_warning}", array("class" => "align_center", "colspan" => 2));
}
else
{
$table->construct_cell("<a href=\"index.php?module=config-plugins&amp;action=activate&amp;plugin={$plugininfo['codename']}&amp;my_post_key={$mybb->post_code}\">{$lang->activate}</a>", array("class" => "align_center", "width" => 150));
if($uninstall_button)
{
$table->construct_cell("<a href=\"index.php?module=config-plugins&amp;action=deactivate&amp;uninstall=1&amp;plugin={$plugininfo['codename']}&amp;my_post_key={$mybb->post_code}\">{$lang->uninstall}</a>", array("class" => "align_center", "width" => 150));
}
else
{
$table->construct_cell("&nbsp;", array("class" => "align_center", "width" => 150));
}
}
}
$table->construct_row();
}
}

View File

@@ -0,0 +1,505 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
// Disallow direct access to this file for security reasons
if(!defined("IN_MYBB"))
{
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
}
$page->add_breadcrumb_item($lang->post_icons, "index.php?module=config-post_icons");
$plugins->run_hooks("admin_config_post_icons_begin");
if($mybb->input['action'] == "add")
{
$plugins->run_hooks("admin_config_post_icons_add");
if($mybb->request_method == "post")
{
if(!trim($mybb->input['name']))
{
$errors[] = $lang->error_missing_name;
}
if(!trim($mybb->input['path']))
{
$errors[] = $lang->error_missing_path;
}
if(!$errors)
{
$new_icon = array(
'name' => $db->escape_string($mybb->input['name']),
'path' => $db->escape_string($mybb->input['path'])
);
$iid = $db->insert_query("icons", $new_icon);
$plugins->run_hooks("admin_config_post_icons_add_commit");
$cache->update_posticons();
// Log admin action
log_admin_action($iid, $mybb->input['name']);
flash_message($lang->success_post_icon_added, 'success');
admin_redirect('index.php?module=config-post_icons');
}
}
$page->add_breadcrumb_item($lang->add_post_icon);
$page->output_header($lang->post_icons." - ".$lang->add_post_icon);
$sub_tabs['manage_icons'] = array(
'title' => $lang->manage_post_icons,
'link' => "index.php?module=config-post_icons"
);
$sub_tabs['add_icon'] = array(
'title' => $lang->add_post_icon,
'link' => "index.php?module=config-post_icons&amp;action=add",
'description' => $lang->add_post_icon_desc
);
$sub_tabs['add_multiple'] = array(
'title' => $lang->add_multiple_post_icons,
'link' => "index.php?module=config-post_icons&amp;action=add_multiple"
);
$page->output_nav_tabs($sub_tabs, 'add_icon');
if($errors)
{
$page->output_inline_error($errors);
}
else
{
$mybb->input['path'] = 'images/icons/';
}
$form = new Form("index.php?module=config-post_icons&amp;action=add", "post", "add");
$form_container = new FormContainer($lang->add_post_icon);
$form_container->output_row($lang->name." <em>*</em>", $lang->name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name');
$form_container->output_row($lang->image_path." <em>*</em>", $lang->image_path_desc, $form->generate_text_box('path', $mybb->input['path'], array('id' => 'path')), 'path');
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_post_icon);
$form->output_submit_wrapper($buttons);
$form->end();
$page->output_footer();
}
if($mybb->input['action'] == "add_multiple")
{
$plugins->run_hooks("admin_config_post_icons_add_multiple");
if($mybb->request_method == "post")
{
if($mybb->input['step'] == 1)
{
if(!trim($mybb->input['pathfolder']))
{
$errors[] = $lang->error_missing_path_multiple;
}
$path = $mybb->input['pathfolder'];
$dir = @opendir(MYBB_ROOT.$path);
if(!$dir)
{
$errors[] = $lang->error_invalid_path;
}
if(substr($path, -1, 1) !== "/")
{
$path .= "/";
}
$query = $db->simple_select("icons");
$aicons = array();
while($icon = $db->fetch_array($query))
{
$aicons[$icon['path']] = 1;
}
$icons = array();
if(!$errors)
{
while($file = readdir($dir))
{
if($file != ".." && $file != ".")
{
$ext = get_extension($file);
if($ext == "gif" || $ext == "jpg" || $ext == "jpeg" || $ext == "png" || $ext == "bmp")
{
if(!$aicons[$path.$file])
{
$icons[] = $file;
}
}
}
}
closedir($dir);
if(count($icons) == 0)
{
$errors[] = $lang->error_no_images;
}
}
// Check for errors again (from above statement)!
if(!$errors)
{
// We have no errors so let's proceed!
$page->add_breadcrumb_item($lang->add_multiple_post_icons);
$page->output_header($lang->post_icons." - ".$lang->add_multiple_post_icons);
$sub_tabs['manage_icons'] = array(
'title' => $lang->manage_post_icons,
'link' => "index.php?module=config-post_icons"
);
$sub_tabs['add_icon'] = array(
'title' => $lang->add_post_icon,
'link' => "index.php?module=config-post_icons&amp;action=add"
);
$sub_tabs['add_multiple'] = array(
'title' => $lang->add_multiple_post_icons,
'link' => "index.php?module=config-post_icons&amp;action=add_multiple",
'description' => $lang->add_multiple_post_icons_desc
);
$page->output_nav_tabs($sub_tabs, 'add_multiple');
$form = new Form("index.php?module=config-post_icons&amp;action=add_multiple", "post", "add_multiple");
echo $form->generate_hidden_field("step", "2");
echo $form->generate_hidden_field("pathfolder", $path);
$form_container = new FormContainer($lang->add_multiple_post_icons);
$form_container->output_row_header($lang->image, array("class" => "align_center", 'width' => '10%'));
$form_container->output_row_header($lang->name);
$form_container->output_row_header($lang->add, array("class" => "align_center", 'width' => '5%'));
foreach($icons as $key => $file)
{
$ext = get_extension($file);
$find = str_replace(".".$ext, "", $file);
$name = ucfirst($find);
$form_container->output_cell("<img src=\"../".$path.$file."\" alt=\"\" /><br /><small>{$file}</small>", array("class" => "align_center", "width" => 1));
$form_container->output_cell($form->generate_text_box("name[{$file}]", $name, array('id' => 'name', 'style' => 'width: 98%')));
$form_container->output_cell($form->generate_check_box("include[{$file}]", 1, "", array('checked' => 1)), array("class" => "align_center"));
$form_container->construct_row();
}
if($form_container->num_rows() == 0)
{
flash_message($lang->error_no_images, 'error');
admin_redirect("index.php?module=config-post_icons&action=add_multiple");
}
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_post_icons);
$form->output_submit_wrapper($buttons);
$form->end();
$page->output_footer();
exit;
}
}
else
{
$path = $mybb->input['pathfolder'];
reset($mybb->input['include']);
$name = $mybb->input['name'];
if(empty($mybb->input['include']))
{
flash_message($lang->error_none_included, 'error');
admin_redirect("index.php?module=config-post_icons&action=add_multiple");
}
foreach($mybb->input['include'] as $image => $insert)
{
if($insert)
{
$new_icon = array(
'name' => $db->escape_string($name[$image]),
'path' => $db->escape_string($path.$image)
);
$db->insert_query("icons", $new_icon);
}
}
$plugins->run_hooks("admin_config_post_icons_add_multiple_commit");
$cache->update_posticons();
// Log admin action
log_admin_action();
flash_message($lang->success_post_icons_added, 'success');
admin_redirect("index.php?module=config-post_icons");
}
}
$page->add_breadcrumb_item($lang->add_multiple_post_icons);
$page->output_header($lang->post_icons." - ".$lang->add_multiple_post_icons);
$sub_tabs['manage_icons'] = array(
'title' => $lang->manage_post_icons,
'link' => "index.php?module=config-post_icons"
);
$sub_tabs['add_icon'] = array(
'title' => $lang->add_post_icon,
'link' => "index.php?module=config-post_icons&amp;action=add"
);
$sub_tabs['add_multiple'] = array(
'title' => $lang->add_multiple_post_icons,
'link' => "index.php?module=config-post_icons&amp;action=add_multiple",
'description' => $lang->add_multiple_post_icons_desc
);
$page->output_nav_tabs($sub_tabs, 'add_multiple');
$form = new Form("index.php?module=config-post_icons&amp;action=add_multiple", "post", "add_multiple");
echo $form->generate_hidden_field("step", "1");
if($errors)
{
$page->output_inline_error($errors);
}
$form_container = new FormContainer($lang->add_multiple_post_icons);
$form_container->output_row($lang->path_to_images." <em>*</em>", $lang->path_to_images_desc, $form->generate_text_box('pathfolder', $mybb->input['pathfolder'], array('id' => 'pathfolder')), 'pathfolder');
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->show_post_icons);
$form->output_submit_wrapper($buttons);
$form->end();
$page->output_footer();
}
if($mybb->input['action'] == "edit")
{
$query = $db->simple_select("icons", "*", "iid='".$mybb->get_input('iid', MyBB::INPUT_INT)."'");
$icon = $db->fetch_array($query);
if(!$icon['iid'])
{
flash_message($lang->error_invalid_post_icon, 'error');
admin_redirect("index.php?module=config-post_icons");
}
$plugins->run_hooks("admin_config_post_icons_edit");
if($mybb->request_method == "post")
{
if(!trim($mybb->input['name']))
{
$errors[] = $lang->error_missing_name;
}
if(!trim($mybb->input['path']))
{
$errors[] = $lang->error_missing_path;
}
if(!$errors)
{
$updated_icon = array(
'name' => $db->escape_string($mybb->input['name']),
'path' => $db->escape_string($mybb->input['path'])
);
$plugins->run_hooks("admin_config_post_icons_edit_commit");
$db->update_query("icons", $updated_icon, "iid='{$icon['iid']}'");
$cache->update_posticons();
// Log admin action
log_admin_action($icon['iid'], $mybb->input['name']);
flash_message($lang->success_post_icon_updated, 'success');
admin_redirect('index.php?module=config-post_icons');
}
}
$page->add_breadcrumb_item($lang->edit_post_icon);
$page->output_header($lang->post_icons." - ".$lang->edit_post_icon);
$sub_tabs['edit_icon'] = array(
'title' => $lang->edit_post_icon,
'link' => "index.php?module=config-post_icons",
'description' => $lang->edit_post_icon_desc
);
$page->output_nav_tabs($sub_tabs, 'edit_icon');
$form = new Form("index.php?module=config-post_icons&amp;action=edit", "post", "edit");
echo $form->generate_hidden_field("iid", $icon['iid']);
if($errors)
{
$page->output_inline_error($errors);
}
else
{
$mybb->input = array_merge($mybb->input, $icon);
}
$form_container = new FormContainer($lang->edit_post_icon);
$form_container->output_row($lang->name." <em>*</em>", $lang->name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name');
$form_container->output_row($lang->image_path." <em>*</em>", $lang->image_path_desc, $form->generate_text_box('path', $mybb->input['path'], array('id' => 'path')), 'path');
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_post_icon);
$buttons[] = $form->generate_reset_button($lang->reset);
$form->output_submit_wrapper($buttons);
$form->end();
$page->output_footer();
}
if($mybb->input['action'] == "delete")
{
$query = $db->simple_select("icons", "*", "iid='".$mybb->get_input('iid', MyBB::INPUT_INT)."'");
$icon = $db->fetch_array($query);
if(!$icon['iid'])
{
flash_message($lang->error_invalid_post_icon, 'error');
admin_redirect("index.php?module=config-post_icons");
}
// User clicked no
if($mybb->input['no'])
{
admin_redirect("index.php?module=config-post_icons");
}
$plugins->run_hooks("admin_config_post_icons_delete");
if($mybb->request_method == "post")
{
$db->delete_query("icons", "iid='{$icon['iid']}'");
$plugins->run_hooks("admin_config_post_icons_delete_commit");
$cache->update_posticons();
// Log admin action
log_admin_action($icon['iid'], $icon['name']);
flash_message($lang->success_post_icon_deleted, 'success');
admin_redirect("index.php?module=config-post_icons");
}
else
{
$page->output_confirm_action("index.php?module=config-post_icons&amp;action=delete&amp;iid={$icon['iid']}", $lang->confirm_post_icon_deletion);
}
}
if(!$mybb->input['action'])
{
$plugins->run_hooks("admin_config_post_icons_start");
$page->output_header($lang->post_icons);
$sub_tabs['manage_icons'] = array(
'title' => $lang->manage_post_icons,
'link' => "index.php?module=config-post_icons",
'description' => $lang->manage_post_icons_desc
);
$sub_tabs['add_icon'] = array(
'title' => $lang->add_post_icon,
'link' => "index.php?module=config-post_icons&amp;action=add"
);
$sub_tabs['add_multiple'] = array(
'title' => $lang->add_multiple_post_icons,
'link' => "index.php?module=config-post_icons&amp;action=add_multiple"
);
$page->output_nav_tabs($sub_tabs, 'manage_icons');
$query = $db->simple_select("icons", "COUNT(iid) AS icons");
$total_rows = $db->fetch_field($query, "icons");
$pagenum = $mybb->get_input('page', MyBB::INPUT_INT);
if($pagenum)
{
$start = ($pagenum - 1) * 20;
$pages = ceil($total_rows / 20);
if($pagenum > $pages)
{
$start = 0;
$pagenum = 1;
}
}
else
{
$start = 0;
$pagenum = 1;
}
$table = new Table;
$table->construct_header($lang->image, array('class' => "align_center", 'width' => 1));
$table->construct_header($lang->name, array('width' => "70%"));
$table->construct_header($lang->controls, array('class' => "align_center", 'colspan' => 2));
$query = $db->simple_select("icons", "*", "", array('limit_start' => $start, 'limit' => 20, 'order_by' => 'name'));
while($icon = $db->fetch_array($query))
{
$icon['path'] = str_replace("{theme}", "images", $icon['path']);
if(my_validate_url($icon['path'], true))
{
$image = $icon['path'];
}
else
{
$image = "../".$icon['path'];
}
$table->construct_cell("<img src=\"".htmlspecialchars_uni($image)."\" alt=\"\" />", array("class" => "align_center"));
$table->construct_cell(htmlspecialchars_uni($icon['name']));
$table->construct_cell("<a href=\"index.php?module=config-post_icons&amp;action=edit&amp;iid={$icon['iid']}\">{$lang->edit}</a>", array("class" => "align_center"));
$table->construct_cell("<a href=\"index.php?module=config-post_icons&amp;action=delete&amp;iid={$icon['iid']}&amp;my_post_key={$mybb->post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_post_icon_deletion}')\">{$lang->delete}</a>", array("class" => "align_center"));
$table->construct_row();
}
if($table->num_rows() == 0)
{
$table->construct_cell($lang->no_post_icons, array('colspan' => 4));
$table->construct_row();
}
$table->output($lang->manage_post_icons);
echo "<br />".draw_admin_pagination($pagenum, "20", $total_rows, "index.php?module=config-post_icons&amp;page={page}");
$page->output_footer();
}

View File

@@ -0,0 +1,795 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
// Disallow direct access to this file for security reasons
if(!defined("IN_MYBB"))
{
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
}
$page->add_breadcrumb_item($lang->custom_profile_fields, "index.php?module=config-profile_fields");
$plugins->run_hooks("admin_config_profile_fields_begin");
if($mybb->input['action'] == "add")
{
$plugins->run_hooks("admin_config_profile_fields_add");
if($mybb->request_method == "post")
{
if(!trim($mybb->input['name']))
{
$errors[] = $lang->error_missing_name;
}
if(!trim($mybb->input['description']))
{
$errors[] = $lang->error_missing_description;
}
if(!trim($mybb->input['fieldtype']))
{
$errors[] = $lang->error_missing_fieldtype;
}
if(!$errors)
{
$type = $mybb->input['fieldtype'];
$options = preg_replace("#(\r\n|\r|\n)#s", "\n", trim($mybb->input['options']));
if($type != "text" && $type != "textarea")
{
$thing = "$type\n$options";
}
else
{
$thing = $type;
}
foreach(array('viewableby', 'editableby') as $key)
{
if($mybb->input[$key] == 'all')
{
$mybb->input[$key] = -1;
}
elseif($mybb->input[$key] == 'custom')
{
if(isset($mybb->input['select'][$key]) && is_array($mybb->input['select'][$key]))
{
foreach($mybb->input['select'][$key] as &$val)
{
$val = (int)$val;
}
unset($val);
$mybb->input[$key] = implode(',', (array)$mybb->input['select'][$key]);
}
else
{
$mybb->input[$key] = '';
}
}
else
{
$mybb->input[$key] = '';
}
}
$new_profile_field = array(
"name" => $db->escape_string($mybb->input['name']),
"description" => $db->escape_string($mybb->input['description']),
"disporder" => $mybb->get_input('disporder', MyBB::INPUT_INT),
"type" => $db->escape_string($thing),
"regex" => $db->escape_string($mybb->input['regex']),
"length" => $mybb->get_input('length', MyBB::INPUT_INT),
"maxlength" => $mybb->get_input('maxlength', MyBB::INPUT_INT),
"required" => $mybb->get_input('required', MyBB::INPUT_INT),
"registration" => $mybb->get_input('registration', MyBB::INPUT_INT),
"profile" => $mybb->get_input('profile', MyBB::INPUT_INT),
"viewableby" => $db->escape_string($mybb->input['viewableby']),
"editableby" => $db->escape_string($mybb->input['editableby']),
"postbit" => $mybb->get_input('postbit', MyBB::INPUT_INT),
"postnum" => $mybb->get_input('postnum', MyBB::INPUT_INT),
"allowhtml" => $mybb->get_input('allowhtml', MyBB::INPUT_INT),
"allowmycode" => $mybb->get_input('allowmycode', MyBB::INPUT_INT),
"allowsmilies" => $mybb->get_input('allowsmilies', MyBB::INPUT_INT),
"allowimgcode" => $mybb->get_input('allowimgcode', MyBB::INPUT_INT),
"allowvideocode" => $mybb->get_input('allowvideocode', MyBB::INPUT_INT)
);
$fid = $db->insert_query("profilefields", $new_profile_field);
$db->write_query("ALTER TABLE ".TABLE_PREFIX."userfields ADD fid{$fid} TEXT");
$plugins->run_hooks("admin_config_profile_fields_add_commit");
$cache->update_profilefields();
// Log admin action
log_admin_action($fid, $mybb->input['name']);
flash_message($lang->success_profile_field_added, 'success');
admin_redirect("index.php?module=config-profile_fields");
}
}
$page->add_breadcrumb_item($lang->add_new_profile_field);
$page->output_header($lang->custom_profile_fields." - ".$lang->add_new_profile_field);
$sub_tabs['custom_profile_fields'] = array(
'title' => $lang->custom_profile_fields,
'link' => "index.php?module=config-profile_fields"
);
$sub_tabs['add_profile_field'] = array(
'title' => $lang->add_new_profile_field,
'link' => "index.php?module=config-profile_fields&amp;action=add",
'description' => $lang->add_new_profile_field_desc
);
$page->output_nav_tabs($sub_tabs, 'add_profile_field');
$form = new Form("index.php?module=config-profile_fields&amp;action=add", "post", "add");
if($errors)
{
switch($mybb->input['viewableby'])
{
case 'all':
$mybb->input['viewableby'] = -1;
break;
case 'custom':
$mybb->input['viewableby'] = implode(',', (array)$mybb->input['select']['viewableby']);
break;
default:
$mybb->input['viewableby'] = '';
break;
}
switch($mybb->input['editableby'])
{
case 'all':
$mybb->input['editableby'] = -1;
break;
case 'custom':
$mybb->input['editableby'] = implode(',', (array)$mybb->input['select']['editableby']);
break;
default:
$mybb->input['editableby'] = '';
break;
}
$page->output_inline_error($errors);
}
else
{
$mybb->input['fieldtype'] = 'textbox';
$mybb->input['required'] = 0;
$mybb->input['registration'] = 0;
$mybb->input['editable'] = 1;
$mybb->input['hidden'] = 0;
$mybb->input['postbit'] = 0;
}
if(empty($mybb->input['viewableby']))
{
$mybb->input['viewableby'] = '';
}
if(empty($mybb->input['editableby']))
{
$mybb->input['editableby'] = '';
}
$form_container = new FormContainer($lang->add_new_profile_field);
$form_container->output_row($lang->title." <em>*</em>", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name');
$form_container->output_row($lang->short_description." <em>*</em>", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description');
$select_list = array(
"text" => $lang->text,
"textarea" => $lang->textarea,
"select" => $lang->select,
"multiselect" => $lang->multiselect,
"radio" => $lang->radio,
"checkbox" => $lang->checkbox
);
$form_container->output_row($lang->field_type." <em>*</em>", $lang->field_type_desc, $form->generate_select_box('fieldtype', $select_list, $mybb->input['fieldtype'], array('id' => 'fieldtype')), 'fieldtype');
$form_container->output_row($lang->field_regex, $lang->field_regex_desc, $form->generate_text_box('regex', $mybb->input['regex'], array('id' => 'regex')), 'regex', array(), array('id' => 'row_regex'));
$form_container->output_row($lang->maximum_length, $lang->maximum_length_desc, $form->generate_numeric_field('maxlength', $mybb->input['maxlength'], array('id' => 'maxlength', 'min' => 0)), 'maxlength', array(), array('id' => 'row_maxlength'));
$form_container->output_row($lang->field_length, $lang->field_length_desc, $form->generate_numeric_field('length', $mybb->input['length'], array('id' => 'length', 'min' => 0)), 'length', array(), array('id' => 'row_fieldlength'));
$form_container->output_row($lang->selectable_options, $lang->selectable_options_desc, $form->generate_text_area('options', $mybb->input['options'], array('id' => 'options')), 'options', array(), array('id' => 'row_options'));
$form_container->output_row($lang->min_posts_enabled, $lang->min_posts_enabled_desc, $form->generate_numeric_field('postnum', $mybb->input['postnum'], array('id' => 'postnum', 'min' => 0)), 'postnum');
$form_container->output_row($lang->display_order." <em>*</em>", $lang->display_order_desc, $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder', 'min' => 0)), 'disporder');
$form_container->output_row($lang->required." <em>*</em>", $lang->required_desc, $form->generate_yes_no_radio('required', $mybb->input['required']));
$form_container->output_row($lang->show_on_registration." <em>*</em>", $lang->show_on_registration_desc, $form->generate_yes_no_radio('registration', $mybb->input['registration']));
$form_container->output_row($lang->display_on_profile." <em>*</em>", $lang->display_on_profile_desc, $form->generate_yes_no_radio('profile', $mybb->input['profile']));
$form_container->output_row($lang->display_on_postbit." <em>*</em>", $lang->display_on_postbit_desc, $form->generate_yes_no_radio('postbit', $mybb->input['postbit']));
$selected_values = '';
if($mybb->input['viewableby'] != '' && $mybb->input['viewableby'] != -1)
{
$selected_values = explode(',', $mybb->get_input('viewableby'));
foreach($selected_values as &$value)
{
$value = (int)$value;
}
unset($value);
}
$group_checked = array('all' => '', 'custom' => '', 'none' => '');
if($mybb->input['viewableby'] == -1)
{
$group_checked['all'] = 'checked="checked"';
}
elseif($mybb->input['viewableby'] != '')
{
$group_checked['custom'] = 'checked="checked"';
}
else
{
$group_checked['none'] = 'checked="checked"';
}
print_selection_javascript();
$select_code = "
<dl style=\"margin-top: 0; margin-bottom: 0; width: 100%\">
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"viewableby\" value=\"all\" {$group_checked['all']} class=\"viewableby_forums_groups_check\" onclick=\"checkAction('viewableby');\" style=\"vertical-align: middle;\" /> <strong>{$lang->all_groups}</strong></label></dt>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"viewableby\" value=\"custom\" {$group_checked['custom']} class=\"viewableby_forums_groups_check\" onclick=\"checkAction('viewableby');\" style=\"vertical-align: middle;\" /> <strong>{$lang->select_groups}</strong></label></dt>
<dd style=\"margin-top: 4px;\" id=\"viewableby_forums_groups_custom\" class=\"viewableby_forums_groups\">
<table cellpadding=\"4\">
<tr>
<td valign=\"top\"><small>{$lang->groups_colon}</small></td>
<td>".$form->generate_group_select('select[viewableby][]', $selected_values, array('id' => 'viewableby', 'multiple' => true, 'size' => 5))."</td>
</tr>
</table>
</dd>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"viewableby\" value=\"none\" {$group_checked['none']} class=\"viewableby_forums_groups_check\" onclick=\"checkAction('viewableby');\" style=\"vertical-align: middle;\" /> <strong>{$lang->none}</strong></label></dt>
</dl>
<script type=\"text/javascript\">
checkAction('viewableby');
</script>";
$form_container->output_row($lang->viewableby, $lang->viewableby_desc, $select_code, '', array(), array('id' => 'row_viewableby'));
$selected_values = '';
if($mybb->input['editableby'] != '' && $mybb->input['editableby'] != -1)
{
$selected_values = explode(',', $mybb->get_input('editableby'));
foreach($selected_values as &$value)
{
$value = (int)$value;
}
unset($value);
}
$group_checked = array('all' => '', 'custom' => '', 'none' => '');
if($mybb->input['editableby'] == -1)
{
$group_checked['all'] = 'checked="checked"';
}
elseif($mybb->input['editableby'] != '')
{
$group_checked['custom'] = 'checked="checked"';
}
else
{
$group_checked['none'] = 'checked="checked"';
}
print_selection_javascript();
$select_code = "
<dl style=\"margin-top: 0; margin-bottom: 0; width: 100%\">
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"editableby\" value=\"all\" {$group_checked['all']} class=\"editableby_forums_groups_check\" onclick=\"checkAction('editableby');\" style=\"vertical-align: middle;\" /> <strong>{$lang->all_groups}</strong></label></dt>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"editableby\" value=\"custom\" {$group_checked['custom']} class=\"editableby_forums_groups_check\" onclick=\"checkAction('editableby');\" style=\"vertical-align: middle;\" /> <strong>{$lang->select_groups}</strong></label></dt>
<dd style=\"margin-top: 4px;\" id=\"editableby_forums_groups_custom\" class=\"editableby_forums_groups\">
<table cellpadding=\"4\">
<tr>
<td valign=\"top\"><small>{$lang->groups_colon}</small></td>
<td>".$form->generate_group_select('select[editableby][]', $selected_values, array('id' => 'editableby', 'multiple' => true, 'size' => 5))."</td>
</tr>
</table>
</dd>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"editableby\" value=\"none\" {$group_checked['none']} class=\"editableby_forums_groups_check\" onclick=\"checkAction('editableby');\" style=\"vertical-align: middle;\" /> <strong>{$lang->none}</strong></label></dt>
</dl>
<script type=\"text/javascript\">
checkAction('editableby');
</script>";
$form_container->output_row($lang->editableby, $lang->editableby_desc, $select_code, '', array(), array('id' => 'row_editableby'));
$parser_options = array(
$form->generate_check_box('allowhtml', 1, $lang->parse_allowhtml, array('checked' => $mybb->input['allowhtml'], 'id' => 'allowhtml')),
$form->generate_check_box('allowmycode', 1, $lang->parse_allowmycode, array('checked' => $mybb->input['allowmycode'], 'id' => 'allowmycode')),
$form->generate_check_box('allowsmilies', 1, $lang->parse_allowsmilies, array('checked' => $mybb->input['allowsmilies'], 'id' => 'allowsmilies')),
$form->generate_check_box('allowimgcode', 1, $lang->parse_allowimgcode, array('checked' => $mybb->input['allowimgcode'], 'id' => 'allowimgcode')),
$form->generate_check_box('allowvideocode', 1, $lang->parse_allowvideocode, array('checked' => $mybb->input['allowvideocode'], 'id' => 'allowvideocode'))
);
$form_container->output_row($lang->parser_options, '', implode('<br />', $parser_options), '', array(), array('id' => 'row_parser_options'));
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_profile_field);
$form->output_submit_wrapper($buttons);
$form->end();
echo '<script type="text/javascript" src="./jscripts/peeker.js?ver=1821"></script>
<script type="text/javascript">
$(function() {
new Peeker($("#fieldtype"), $("#row_maxlength, #row_regex, #row_parser_options"), /text|textarea/, false);
new Peeker($("#fieldtype"), $("#row_fieldlength"), /select|multiselect/, false);
new Peeker($("#fieldtype"), $("#row_options"), /select|radio|checkbox/, false);
// Add a star to the extra row since the "extra" is required if the box is shown
add_star("row_maxlength");
add_star("row_fieldlength");
add_star("row_options");
});
</script>';
$page->output_footer();
}
if($mybb->input['action'] == "edit")
{
$query = $db->simple_select("profilefields", "*", "fid = '".$mybb->get_input('fid', MyBB::INPUT_INT)."'");
$profile_field = $db->fetch_array($query);
if(!$profile_field['fid'])
{
flash_message($lang->error_invalid_fid, 'error');
admin_redirect("index.php?module=config-profile_fields");
}
$plugins->run_hooks("admin_config_profile_fields_edit");
if($mybb->request_method == "post")
{
if(!trim($mybb->input['name']))
{
$errors[] = $lang->error_missing_name;
}
if(!trim($mybb->input['description']))
{
$errors[] = $lang->error_missing_description;
}
if(!trim($mybb->input['fieldtype']))
{
$errors[] = $lang->error_missing_fieldtype;
}
$type = $mybb->input['fieldtype'];
$options = preg_replace("#(\r\n|\r|\n)#s", "\n", trim($mybb->input['options']));
if($type != "text" && $type != "textarea")
{
$type = "$type\n$options";
}
if(!$errors)
{
foreach(array('viewableby', 'editableby') as $key)
{
if($mybb->input[$key] == 'all')
{
$mybb->input[$key] = -1;
}
elseif($mybb->input[$key] == 'custom')
{
if(isset($mybb->input['select'][$key]) && is_array($mybb->input['select'][$key]))
{
foreach($mybb->input['select'][$key] as &$val)
{
$val = (int)$val;
}
unset($val);
$mybb->input[$key] = implode(',', (array)$mybb->input['select'][$key]);
}
else
{
$mybb->input[$key] = '';
}
}
else
{
$mybb->input[$key] = '';
}
}
$updated_profile_field = array(
"name" => $db->escape_string($mybb->input['name']),
"description" => $db->escape_string($mybb->input['description']),
"disporder" => $mybb->get_input('disporder', MyBB::INPUT_INT),
"type" => $db->escape_string($type),
"regex" => $db->escape_string($mybb->input['regex']),
"length" => $mybb->get_input('length', MyBB::INPUT_INT),
"maxlength" => $mybb->get_input('maxlength', MyBB::INPUT_INT),
"required" => $mybb->get_input('required', MyBB::INPUT_INT),
"registration" => $mybb->get_input('registration', MyBB::INPUT_INT),
"profile" => $mybb->get_input('profile', MyBB::INPUT_INT),
"viewableby" => $db->escape_string($mybb->input['viewableby']),
"editableby" => $db->escape_string($mybb->input['editableby']),
"postbit" => $mybb->get_input('postbit', MyBB::INPUT_INT),
"postnum" => $mybb->get_input('postnum', MyBB::INPUT_INT),
"allowhtml" => $mybb->get_input('allowhtml', MyBB::INPUT_INT),
"allowmycode" => $mybb->get_input('allowmycode', MyBB::INPUT_INT),
"allowsmilies" => $mybb->get_input('allowsmilies', MyBB::INPUT_INT),
"allowimgcode" => $mybb->get_input('allowimgcode', MyBB::INPUT_INT),
"allowvideocode" => $mybb->get_input('allowvideocode', MyBB::INPUT_INT)
);
$plugins->run_hooks("admin_config_profile_fields_edit_commit");
$db->update_query("profilefields", $updated_profile_field, "fid='{$profile_field['fid']}'");
$cache->update_profilefields();
// Log admin action
log_admin_action($profile_field['fid'], $mybb->input['name']);
flash_message($lang->success_profile_field_saved, 'success');
admin_redirect("index.php?module=config-profile_fields");
}
}
$page->add_breadcrumb_item($lang->edit_profile_field);
$page->output_header($lang->custom_profile_fields." - ".$lang->edit_profile_field);
$sub_tabs['edit_profile_field'] = array(
'title' => $lang->edit_profile_field,
'link' => "index.php?module=config-profile_fields&amp;action=edit&amp;fid={$profile_field['fid']}",
'description' => $lang->edit_profile_field_desc
);
$page->output_nav_tabs($sub_tabs, 'edit_profile_field');
$form = new Form("index.php?module=config-profile_fields&amp;action=edit", "post", "edit");
echo $form->generate_hidden_field("fid", $profile_field['fid']);
if($errors)
{
switch($mybb->input['viewableby'])
{
case 'all':
$mybb->input['viewableby'] = -1;
break;
case 'custom':
$mybb->input['viewableby'] = implode(',', (array)$mybb->input['select']['viewableby']);
break;
default:
$mybb->input['viewableby'] = '';
break;
}
switch($mybb->input['editableby'])
{
case 'all':
$mybb->input['editableby'] = -1;
break;
case 'custom':
$mybb->input['editableby'] = implode(',', (array)$mybb->input['select']['editableby']);
break;
default:
$mybb->input['editableby'] = '';
break;
}
$page->output_inline_error($errors);
}
else
{
$type = explode("\n", $profile_field['type'], "2");
$mybb->input = $profile_field;
$mybb->input['fieldtype'] = $type[0];
$mybb->input['options'] = $type[1];
}
if(empty($mybb->input['viewableby']))
{
$mybb->input['viewableby'] = '';
}
if(empty($mybb->input['editableby']))
{
$mybb->input['editableby'] = '';
}
$form_container = new FormContainer($lang->edit_profile_field);
$form_container->output_row($lang->title." <em>*</em>", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name');
$form_container->output_row($lang->short_description." <em>*</em>", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description');
$select_list = array(
"text" => $lang->text,
"textarea" => $lang->textarea,
"select" => $lang->select,
"multiselect" => $lang->multiselect,
"radio" => $lang->radio,
"checkbox" => $lang->checkbox
);
$form_container->output_row($lang->field_type." <em>*</em>", $lang->field_type_desc, $form->generate_select_box('fieldtype', $select_list, $mybb->input['fieldtype'], array('id' => 'fieldtype')), 'fieldtype');
$form_container->output_row($lang->field_regex, $lang->field_regex_desc, $form->generate_text_box('regex', $mybb->input['regex'], array('id' => 'regex')), 'regex', array(), array('id' => 'row_regex'));
$form_container->output_row($lang->maximum_length, $lang->maximum_length_desc, $form->generate_numeric_field('maxlength', $mybb->input['maxlength'], array('id' => 'maxlength', 'min' => 0)), 'maxlength', array(), array('id' => 'row_maxlength'));
$form_container->output_row($lang->field_length, $lang->field_length_desc, $form->generate_numeric_field('length', $mybb->input['length'], array('id' => 'length', 'min' => 0)), 'length', array(), array('id' => 'row_fieldlength'));
$form_container->output_row($lang->selectable_options, $lang->selectable_options_desc, $form->generate_text_area('options', $mybb->input['options'], array('id' => 'options')), 'options', array(), array('id' => 'row_options'));
$form_container->output_row($lang->min_posts_enabled, $lang->min_posts_enabled_desc, $form->generate_numeric_field('postnum', $mybb->input['postnum'], array('id' => 'postnum', 'min' => 0)), 'postnum');
$form_container->output_row($lang->display_order." <em>*</em>", $lang->display_order_desc, $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder', 'min' => 0)), 'disporder');
$form_container->output_row($lang->required." <em>*</em>", $lang->required_desc, $form->generate_yes_no_radio('required', $mybb->input['required']));
$form_container->output_row($lang->show_on_registration." <em>*</em>", $lang->show_on_registration_desc, $form->generate_yes_no_radio('registration', $mybb->input['registration']));
$form_container->output_row($lang->display_on_profile." <em>*</em>", $lang->display_on_profile_desc, $form->generate_yes_no_radio('profile', $mybb->input['profile']));
$form_container->output_row($lang->display_on_postbit." <em>*</em>", $lang->display_on_postbit_desc, $form->generate_yes_no_radio('postbit', $mybb->input['postbit']));
$selected_values = '';
if($mybb->input['viewableby'] != '' && $mybb->input['viewableby'] != -1)
{
$selected_values = explode(',', $mybb->get_input('viewableby'));
foreach($selected_values as &$value)
{
$value = (int)$value;
}
unset($value);
}
$group_checked = array('all' => '', 'custom' => '', 'none' => '');
if($mybb->input['viewableby'] == -1)
{
$group_checked['all'] = 'checked="checked"';
}
elseif($mybb->input['viewableby'] != '')
{
$group_checked['custom'] = 'checked="checked"';
}
else
{
$group_checked['none'] = 'checked="checked"';
}
print_selection_javascript();
$select_code = "
<dl style=\"margin-top: 0; margin-bottom: 0; width: 100%\">
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"viewableby\" value=\"all\" {$group_checked['all']} class=\"viewableby_forums_groups_check\" onclick=\"checkAction('viewableby');\" style=\"vertical-align: middle;\" /> <strong>{$lang->all_groups}</strong></label></dt>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"viewableby\" value=\"custom\" {$group_checked['custom']} class=\"viewableby_forums_groups_check\" onclick=\"checkAction('viewableby');\" style=\"vertical-align: middle;\" /> <strong>{$lang->select_groups}</strong></label></dt>
<dd style=\"margin-top: 4px;\" id=\"viewableby_forums_groups_custom\" class=\"viewableby_forums_groups\">
<table cellpadding=\"4\">
<tr>
<td valign=\"top\"><small>{$lang->groups_colon}</small></td>
<td>".$form->generate_group_select('select[viewableby][]', $selected_values, array('id' => 'viewableby', 'multiple' => true, 'size' => 5))."</td>
</tr>
</table>
</dd>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"viewableby\" value=\"none\" {$group_checked['none']} class=\"viewableby_forums_groups_check\" onclick=\"checkAction('viewableby');\" style=\"vertical-align: middle;\" /> <strong>{$lang->none}</strong></label></dt>
</dl>
<script type=\"text/javascript\">
checkAction('viewableby');
</script>";
$form_container->output_row($lang->viewableby, $lang->viewableby_desc, $select_code, '', array(), array('id' => 'row_viewableby'));
$selected_values = '';
if($mybb->input['editableby'] != '' && $mybb->input['editableby'] != -1)
{
$selected_values = explode(',', $mybb->get_input('editableby'));
foreach($selected_values as &$value)
{
$value = (int)$value;
}
unset($value);
}
$group_checked = array('all' => '', 'custom' => '', 'none' => '');
if($mybb->input['editableby'] == -1)
{
$group_checked['all'] = 'checked="checked"';
}
elseif($mybb->input['editableby'] != '')
{
$group_checked['custom'] = 'checked="checked"';
}
else
{
$group_checked['none'] = 'checked="checked"';
}
print_selection_javascript();
$select_code = "
<dl style=\"margin-top: 0; margin-bottom: 0; width: 100%\">
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"editableby\" value=\"all\" {$group_checked['all']} class=\"editableby_forums_groups_check\" onclick=\"checkAction('editableby');\" style=\"vertical-align: middle;\" /> <strong>{$lang->all_groups}</strong></label></dt>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"editableby\" value=\"custom\" {$group_checked['custom']} class=\"editableby_forums_groups_check\" onclick=\"checkAction('editableby');\" style=\"vertical-align: middle;\" /> <strong>{$lang->select_groups}</strong></label></dt>
<dd style=\"margin-top: 4px;\" id=\"editableby_forums_groups_custom\" class=\"editableby_forums_groups\">
<table cellpadding=\"4\">
<tr>
<td valign=\"top\"><small>{$lang->groups_colon}</small></td>
<td>".$form->generate_group_select('select[editableby][]', $selected_values, array('id' => 'editableby', 'multiple' => true, 'size' => 5))."</td>
</tr>
</table>
</dd>
<dt><label style=\"display: block;\"><input type=\"radio\" name=\"editableby\" value=\"none\" {$group_checked['none']} class=\"editableby_forums_groups_check\" onclick=\"checkAction('editableby');\" style=\"vertical-align: middle;\" /> <strong>{$lang->none}</strong></label></dt>
</dl>
<script type=\"text/javascript\">
checkAction('editableby');
</script>";
$form_container->output_row($lang->editableby, $lang->editableby_desc, $select_code, '', array(), array('id' => 'row_editableby'));
$parser_options = array(
$form->generate_check_box('allowhtml', 1, $lang->parse_allowhtml, array('checked' => $mybb->input['allowhtml'], 'id' => 'allowhtml')),
$form->generate_check_box('allowmycode', 1, $lang->parse_allowmycode, array('checked' => $mybb->input['allowmycode'], 'id' => 'allowmycode')),
$form->generate_check_box('allowsmilies', 1, $lang->parse_allowsmilies, array('checked' => $mybb->input['allowsmilies'], 'id' => 'allowsmilies')),
$form->generate_check_box('allowimgcode', 1, $lang->parse_allowimgcode, array('checked' => $mybb->input['allowimgcode'], 'id' => 'allowimgcode')),
$form->generate_check_box('allowvideocode', 1, $lang->parse_allowvideocode, array('checked' => $mybb->input['allowvideocode'], 'id' => 'allowvideocode'))
);
$form_container->output_row($lang->parser_options, '', implode('<br />', $parser_options), '', array(), array('id' => 'row_parser_options'));
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_profile_field);
$form->output_submit_wrapper($buttons);
$form->end();
echo '<script type="text/javascript" src="./jscripts/peeker.js?ver=1821"></script>
<script type="text/javascript">
$(function() {
new Peeker($("#fieldtype"), $("#row_maxlength, #row_regex, #row_parser_options"), /text|textarea/);
new Peeker($("#fieldtype"), $("#row_fieldlength"), /select|multiselect/);
new Peeker($("#fieldtype"), $("#row_options"), /select|radio|checkbox/);
// Add a star to the extra row since the "extra" is required if the box is shown
add_star("row_maxlength");
add_star("row_fieldlength");
add_star("row_options");
});
</script>';
$page->output_footer();
}
if($mybb->input['action'] == "delete")
{
$query = $db->simple_select("profilefields", "*", "fid='".$mybb->get_input('fid', MyBB::INPUT_INT)."'");
$profile_field = $db->fetch_array($query);
// Does the profile field not exist?
if(!$profile_field['fid'])
{
flash_message($lang->error_invalid_fid, 'error');
admin_redirect("index.php?module=config-profile_fields");
}
// User clicked no
if($mybb->input['no'])
{
admin_redirect("index.php?module=config-profile_fields");
}
$plugins->run_hooks("admin_config_profile_fields_delete");
if($mybb->request_method == "post")
{
// Delete the profile field
$db->delete_query("profilefields", "fid='{$profile_field['fid']}'");
$db->write_query("ALTER TABLE ".TABLE_PREFIX."userfields DROP fid{$profile_field['fid']}");
$plugins->run_hooks("admin_config_profile_fields_delete_commit");
$cache->update_profilefields();
// Log admin action
log_admin_action($profile_field['fid'], $profile_field['name']);
flash_message($lang->success_profile_field_deleted, 'success');
admin_redirect("index.php?module=config-profile_fields");
}
else
{
$page->output_confirm_action("index.php?module=config-profile_fields&amp;action=delete&amp;fid={$profile_field['fid']}", $lang->confirm_profile_field_deletion);
}
}
if(!$mybb->input['action'])
{
$plugins->run_hooks("admin_config_profile_fields_start");
$page->output_header($lang->custom_profile_fields);
$sub_tabs['custom_profile_fields'] = array(
'title' => $lang->custom_profile_fields,
'link' => "index.php?module=config-profile_fields",
'description' => $lang->custom_profile_fields_desc
);
$sub_tabs['add_profile_field'] = array(
'title' => $lang->add_new_profile_field,
'link' => "index.php?module=config-profile_fields&amp;action=add",
);
$page->output_nav_tabs($sub_tabs, 'custom_profile_fields');
$table = new Table;
$table->construct_header($lang->name);
$table->construct_header($lang->required, array("class" => "align_center"));
$table->construct_header($lang->registration, array("class" => "align_center"));
$table->construct_header($lang->editable, array("class" => "align_center"));
$table->construct_header($lang->profile, array("class" => "align_center"));
$table->construct_header($lang->postbit, array("class" => "align_center"));
$table->construct_header($lang->controls, array("class" => "align_center"));
$query = $db->simple_select("profilefields", "*", "", array('order_by' => 'disporder'));
while($field = $db->fetch_array($query))
{
if($field['required'])
{
$required = $lang->yes;
}
else
{
$required = $lang->no;
}
if($field['registration'])
{
$registration = $lang->yes;
}
else
{
$registration = $lang->no;
}
if($field['editableby'] == '')
{
$editable = $lang->no;
}
else
{
$editable = $lang->yes;
}
if($field['profile'])
{
$profile = $lang->yes;
}
else
{
$profile = $lang->no;
}
if($field['postbit'])
{
$postbit = $lang->yes;
}
else
{
$postbit = $lang->no;
}
$table->construct_cell("<strong><a href=\"index.php?module=config-profile_fields&amp;action=edit&amp;fid={$field['fid']}\">".htmlspecialchars_uni($field['name'])."</a></strong><br /><small>".htmlspecialchars_uni($field['description'])."</small>", array('width' => '35%'));
$table->construct_cell($required, array("class" => "align_center", 'width' => '10%'));
$table->construct_cell($registration, array("class" => "align_center", 'width' => '10%'));
$table->construct_cell($editable, array("class" => "align_center", 'width' => '10%'));
$table->construct_cell($profile, array("class" => "align_center", 'width' => '10%'));
$table->construct_cell($postbit, array("class" => "align_center", 'width' => '10%'));
$popup = new PopupMenu("field_{$field['fid']}", $lang->options);
$popup->add_item($lang->edit_field, "index.php?module=config-profile_fields&amp;action=edit&amp;fid={$field['fid']}");
$popup->add_item($lang->delete_field, "index.php?module=config-profile_fields&amp;action=delete&amp;fid={$field['fid']}&amp;my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_profile_field_deletion}')");
$table->construct_cell($popup->fetch(), array("class" => "align_center", 'width' => '20%'));
$table->construct_row();
}
if($table->num_rows() == 0)
{
$table->construct_cell($lang->no_profile_fields, array('colspan' => 7));
$table->construct_row();
}
$table->output($lang->custom_profile_fields);
$page->output_footer();
}

View File

@@ -0,0 +1,417 @@
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
// Disallow direct access to this file for security reasons
if(!defined("IN_MYBB"))
{
die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
}
$page->add_breadcrumb_item($lang->security_questions, "index.php?module=config-questions");
$plugins->run_hooks("admin_config_questions_begin");
if($mybb->input['action'] == "add")
{
$plugins->run_hooks("admin_config_questions_add");
if($mybb->request_method == "post")
{
if(!trim($mybb->input['question']))
{
$errors[] = $lang->error_missing_question;
}
if(!trim($mybb->input['answer']))
{
$errors[] = $lang->error_missing_answer;
}
if(!$errors)
{
if(!isset($mybb->input['preview']))
{
$answer = preg_replace("#(\r\n|\r|\n)#s", "\n", trim($mybb->input['answer']));
$new_question = array(
"question" => $db->escape_string($mybb->input['question']),
"answer" => $db->escape_string($answer),
"active" => $mybb->get_input('active', MyBB::INPUT_INT)
);
$qid = $db->insert_query("questions", $new_question);
$plugins->run_hooks("admin_config_questions_add_commit");
// Log admin action
log_admin_action($qid, $mybb->input['question']);
flash_message($lang->success_question_created, 'success');
admin_redirect("index.php?module=config-questions");
}
}
}
$page->add_breadcrumb_item($lang->add_new_question);
$page->output_header($lang->security_questions." - ".$lang->add_new_question);
$sub_tabs['security_questions'] = array(
'title' => $lang->security_questions,
'link' => "index.php?module=config-questions"
);
$sub_tabs['add_new_question'] = array(
'title' => $lang->add_new_question,
'link' => "index.php?module=config-questions&amp;action=add",
'description' => $lang->add_new_question_desc
);
$page->output_nav_tabs($sub_tabs, 'add_new_question');
if(isset($mybb->input['preview']) && !$errors)
{
$table = new Table();
require_once MYBB_ROOT."inc/class_parser.php";
$parser = new postParser;
$parser_options = array(
"allow_html" => 0,
"allow_mycode" => 1,
"allow_smilies" => 1,
"allow_imgcode" => 1,
"allow_videocode" => 1,
"filter_badwords" => 1,
"me_username" => 0,
"shorten_urls" => 0,
"highlight" => 0,
);
$table->construct_cell($parser->parse_message($mybb->input['question'], $parser_options));
$table->construct_row();
$table->output($lang->preview_question);
}
$form = new Form("index.php?module=config-questions&amp;action=add", "post", "add");
if($errors)
{
$page->output_inline_error($errors);
}
else
{
$mybb->input['active'] = '1';
}
$form_container = new FormContainer($lang->add_new_question);
$form_container->output_row($lang->question." <em>*</em>", $lang->question_desc, $form->generate_text_area('question', $mybb->input['question'], array('id' => 'question')), 'question');
$form_container->output_row($lang->answers." <em>*</em>", $lang->answers_desc, $form->generate_text_area('answer', $mybb->input['answer'], array('id' => 'answer')), 'answer');
$form_container->output_row($lang->active." <em>*</em>", "", $form->generate_yes_no_radio('active', $mybb->input['active']));
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_question);
$buttons[] = $form->generate_submit_button($lang->preview_question, array('name' => 'preview'));
$form->output_submit_wrapper($buttons);
$form->end();
$page->output_footer();
}
if($mybb->input['action'] == "edit")
{
$query = $db->simple_select("questions", "*", "qid='".$mybb->get_input('qid', MyBB::INPUT_INT)."'");
$question = $db->fetch_array($query);
if(!$question['qid'])
{
flash_message($lang->error_invalid_question, 'error');
admin_redirect("index.php?module=config-questions");
}
$plugins->run_hooks("admin_config_questions_edit");
if($mybb->request_method == "post")
{
if(!trim($mybb->input['question']))
{
$errors[] = $lang->error_missing_question;
}
if(!trim($mybb->input['answer']))
{
$errors[] = $lang->error_missing_answer;
}
if(!$errors)
{
if(!isset($mybb->input['preview']))
{
$answer = preg_replace("#(\r\n|\r|\n)#s", "\n", trim($mybb->input['answer']));
$updated_question = array(
"question" => $db->escape_string($mybb->input['question']),
"answer" => $db->escape_string($answer),
"active" => $mybb->get_input('active', MyBB::INPUT_INT)
);
$plugins->run_hooks("admin_config_questions_edit_commit");
$db->update_query("questions", $updated_question, "qid='{$question['qid']}'");
// Log admin action
log_admin_action($question['qid'], $mybb->input['question']);
flash_message($lang->success_question_updated, 'success');
admin_redirect("index.php?module=config-questions");
}
}
}
$page->add_breadcrumb_item($lang->edit_question);
$page->output_header($lang->security_questions." - ".$lang->edit_question);
$sub_tabs['edit_question'] = array(
'title' => $lang->edit_question,
'link' => "index.php?module=config-questions&amp;action=edit&amp;qid={$question['qid']}",
'description' => $lang->edit_question_desc
);
$page->output_nav_tabs($sub_tabs, 'edit_question');
$form = new Form("index.php?module=config-questions&amp;action=edit&amp;qid={$question['qid']}", "post", "add");
$show_preview = false;
if(isset($mybb->input['preview_list']))
{
$show_preview = true;
}
if($errors)
{
$page->output_inline_error($errors);
}
else
{
if(!isset($mybb->input['preview']))
{
$mybb->input = $question;
}
}
if((isset($mybb->input['preview']) || $show_preview === true) && !$errors)
{
$table = new Table();
require_once MYBB_ROOT."inc/class_parser.php";
$parser = new postParser;
$parser_options = array(
"allow_html" => 0,
"allow_mycode" => 1,
"allow_smilies" => 1,
"allow_imgcode" => 1,
"allow_videocode" => 1,
"filter_badwords" => 1,
"me_username" => 0,
"shorten_urls" => 0,
"highlight" => 0,
);
$table->construct_cell($parser->parse_message($mybb->input['question'], $parser_options));
$table->construct_row();
$table->output($lang->preview_question);
}
$form_container = new FormContainer($lang->edit_question);
$form_container->output_row($lang->question." <em>*</em>", $lang->question_desc, $form->generate_text_area('question', $mybb->input['question'], array('id' => 'question')), 'question');
$form_container->output_row($lang->answers." <em>*</em>", $lang->answers_desc, $form->generate_text_area('answer', $mybb->input['answer'], array('id' => 'answer')), 'answer');
$form_container->output_row($lang->active." <em>*</em>", "", $form->generate_yes_no_radio('active', $mybb->input['active']));
$form_container->end();
$buttons[] = $form->generate_submit_button($lang->save_question);
$buttons[] = $form->generate_submit_button($lang->preview_question, array('name' => 'preview'));
$form->output_submit_wrapper($buttons);
$form->end();
$page->output_footer();
}
if($mybb->input['action'] == "delete")
{
if($mybb->input['no'])
{
admin_redirect("index.php?module=config-questions");
}
$query = $db->simple_select("questions", "*", "qid='".$mybb->get_input('qid', MyBB::INPUT_INT)."'");
$question = $db->fetch_array($query);
if(!$question['qid'])
{
flash_message($lang->error_invalid_question, 'error');
admin_redirect("index.php?module=config-questions");
}
$plugins->run_hooks("admin_config_questions_delete");
if($mybb->request_method == "post")
{
$db->delete_query("questions", "qid='{$question['qid']}'");
$db->delete_query("questionsessions", "qid='{$question['qid']}'");
$plugins->run_hooks("admin_config_questions_delete_commit");
// Log admin action
log_admin_action($question['qid'], $question['question']);
flash_message($lang->success_question_deleted, 'success');
admin_redirect("index.php?module=config-questions");
}
else
{
$page->output_confirm_action("index.php?module=config-questions&amp;action=delete&amp;qid={$question['qid']}", $lang->confirm_question_deletion);
}
}
if($mybb->input['action'] == "disable")
{
$query = $db->simple_select("questions", "*", "qid='".$mybb->get_input('qid', MyBB::INPUT_INT)."'");
$question = $db->fetch_array($query);
if(!$question['qid'])
{
flash_message($lang->error_invalid_question, 'error');
admin_redirect("index.php?module=config-questions");
}
$plugins->run_hooks("admin_config_questions_disable");
$update_question = array(
"active" => 0
);
$plugins->run_hooks("admin_config_questions_disable_commit");
$db->update_query("questions", $update_question, "qid = '{$question['qid']}'");
// Log admin action
log_admin_action($question['qid'], $question['question']);
flash_message($lang->success_question_disabled, 'success');
admin_redirect("index.php?module=config-questions");
}
if($mybb->input['action'] == "enable")
{
$query = $db->simple_select("questions", "*", "qid='".$mybb->get_input('qid', MyBB::INPUT_INT)."'");
$question = $db->fetch_array($query);
if(!$question['qid'])
{
flash_message($lang->error_invalid_question, 'error');
admin_redirect("index.php?module=config-questions");
}
$plugins->run_hooks("admin_config_questions_enable");
$update_question = array(
"active" => 1
);
$plugins->run_hooks("admin_config_questions_enable_commit");
$db->update_query("questions", $update_question, "qid = '{$question['qid']}'");
// Log admin action
log_admin_action($question['qid'], $question['question']);
flash_message($lang->success_question_enabled, 'success');
admin_redirect("index.php?module=config-questions");
}
if(!$mybb->input['action'])
{
$plugins->run_hooks("admin_config_questions_start");
$page->output_header($lang->security_questions);
$sub_tabs['security_questions'] = array(
'title' => $lang->security_questions,
'link' => "index.php?module=config-questions",
'description' => $lang->security_questions_desc
);
$sub_tabs['add_new_question'] = array(
'title' => $lang->add_new_question,
'link' => "index.php?module=config-questions&amp;action=add",
);
$page->output_nav_tabs($sub_tabs, 'security_questions');
$table = new Table;
$table->construct_header($lang->question);
$table->construct_header($lang->answers, array("width" => "35%"));
$table->construct_header($lang->shown, array("width" => "5%", "class" => "align_center"));
$table->construct_header($lang->correct, array("width" => "5%", "class" => "align_center"));
$table->construct_header($lang->incorrect, array("width" => "5%", "class" => "align_center"));
$table->construct_header($lang->controls, array("class" => "align_center", "width" => 150));
$query = $db->simple_select("questions", "*", "", array('order_by' => 'question'));
while($questions = $db->fetch_array($query))
{
$questions['question'] = htmlspecialchars_uni($questions['question']);
$questions['answer'] = htmlspecialchars_uni($questions['answer']);
$questions['answer'] = preg_replace("#(\n)#s", "<br />", trim($questions['answer']));
$questions['shown'] = my_number_format($questions['shown']);
$questions['correct'] = my_number_format($questions['correct']);
$questions['incorrect'] = my_number_format($questions['incorrect']);
if($questions['active'] == 1)
{
$icon = "<img src=\"styles/{$page->style}/images/icons/bullet_on.png\" alt=\"({$lang->alt_enabled})\" title=\"{$lang->alt_enabled}\" style=\"vertical-align: middle;\" /> ";
}
else
{
$icon = "<img src=\"styles/{$page->style}/images/icons/bullet_off.png\" alt=\"({$lang->alt_disabled})\" title=\"{$lang->alt_disabled}\" style=\"vertical-align: middle;\" /> ";
}
$table->construct_cell("<div>{$icon}{$questions['question']}</div>");
$table->construct_cell($questions['answer']);
$table->construct_cell($questions['shown'], array("class" => "align_center"));
$table->construct_cell($questions['correct'], array("class" => "align_center"));
$table->construct_cell($questions['incorrect'], array("class" => "align_center"));
$popup = new PopupMenu("questions_{$questions['qid']}", $lang->options);
$popup->add_item($lang->edit_question, "index.php?module=config-questions&amp;action=edit&amp;qid={$questions['qid']}");
$popup->add_item($lang->preview_question, "index.php?module=config-questions&amp;action=edit&amp;qid={$questions['qid']}&amp;preview_list");
if($questions['active'] == 1)
{
$popup->add_item($lang->disable_question, "index.php?module=config-questions&amp;action=disable&amp;qid={$questions['qid']}&amp;my_post_key={$mybb->post_code}");
}
else
{
$popup->add_item($lang->enable_question, "index.php?module=config-questions&amp;action=enable&amp;qid={$questions['qid']}&amp;my_post_key={$mybb->post_code}");
}
$popup->add_item($lang->delete_question, "index.php?module=config-questions&amp;action=delete&amp;qid={$questions['qid']}&amp;my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_question_deletion}')");
$table->construct_cell($popup->fetch(), array("class" => "align_center"));
$table->construct_row();
}
if($table->num_rows() == 0)
{
$table->construct_cell($lang->no_security_questions, array('colspan' => 6));
$table->construct_row();
}
$table->output($lang->security_questions);
$page->output_footer();
}

Some files were not shown because too many files have changed in this diff Show More