initial commit
46
html/!!!!README 1st!!!!
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
SWG NGE Server Webpage v1.01
|
||||
|
||||
|
||||
|
||||
All Star Wars background pictures, music, and logos are registered trademarks and copyright of LucasArts and Disney. We do not recieve original credit for those trademarks and copyrights in anyway, shape, or form.
|
||||
|
||||
|
||||
|
||||
Modified Webpage:
|
||||
|
||||
I modified the webpage to add backgrounds, music(at main page), extra links, Server Online/Offline Status at Main Page (currently cant find correct port number for $portg but Login Server Status is working. If you accidently delete the port number for the Login Status, it is 10666. just put that in $portl if needed. If someone happens to find the correct port with no errors or crashes, please let us know with the correct port number).
|
||||
|
||||
Currently I have no mysql database and oracle database experience to configure and modify the database for the Number of Players Online status so please let me know if you got this configured and how and what you did.
|
||||
|
||||
Make sure to change the IP addresses in webpage code (not counting 127.0.0.1 in Server Status), to current IP address of VM in lower left corner of VM screen. Bring up a web browser and type in the address bar: http://(your.VM.Address.here) without the (). Then you can refresh the page when you change any of the webpage code.
|
||||
|
||||
|
||||
FORUMS PAGE
|
||||
-------------------------------
|
||||
MyBB v1.8.12
|
||||
|
||||
I have also included a MyBB forums for the site as well. You will also have to add a mySQL database section for the forums before you can install it.
|
||||
|
||||
Copy and paste this link in your browser for MyBB setup instructions and make sure to follow them correctly: https://docs.mybb.com/1.8/install/
|
||||
|
||||
You will need to register a seperate account for the forums.
|
||||
|
||||
|
||||
|
||||
|
||||
May the Force Be With You.
|
||||
|
||||
-----------------------------------------------------------------
|
||||
|
||||
v1.01 UPDATE: 9/10/2017
|
||||
|
||||
1.)Fixed a few links on index.php and 1 link on addnewuser.php:
|
||||
|
||||
a.)index.php: links for home, forums, and Register for an Account on index.php now have "/index.php", "/forums/index.php", and "/addnewuser.php" instead of http://192.168.1.XXX or http://localhost. Now user wont have to set addresses for webpage
|
||||
|
||||
b.) addnewuser.php> fixed "Home" link on addnewuser.php. Instead of it being http://localhost/index.php or http://192.168.1.XXX, it is now /index.php. Now user wont have to set addresses for webpage
|
||||
|
||||
2.) Reconfigured index.php coding to bring the main page up to top of page and menu on left side of page to be the top-left instead of at midd to bottom of page due to html body coding
|
||||
|
||||
|
||||
80
html/addnewuser.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Create a New Account</title>
|
||||
<meta name = "viewport" content = "width = device-width">
|
||||
<meta name = "viewport" content = "initial-scale = 1.0">
|
||||
<script type="text/javascript" language="JavaScript">
|
||||
<!--
|
||||
|
||||
function BothFieldsIdenticalCaseSensitive() {
|
||||
var one = document.NewUser.realpassword.value;
|
||||
var another = document.NewUser.confirmpassword.value;
|
||||
if(one == another) { return true; }
|
||||
alert("Password fields must be the same.");
|
||||
return false;
|
||||
}
|
||||
//-->
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
background-image: url("/images/darth_vader-lightsaber-star_wars.jpg");
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
}
|
||||
a:link {
|
||||
color: green;
|
||||
background-color: transparent;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:visited {
|
||||
color: orange;
|
||||
background-color: transparent;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
color: red;
|
||||
background-color: transparent;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:active {
|
||||
color: yellow;
|
||||
background-color: transparent;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<body style="font-family: arial; font-style: gill-sans">
|
||||
<p><center><b><a href="/index.php">Home</a></b></p>
|
||||
<table>
|
||||
<form name="NewUser" action="newuserpost.php" method="post" border="0">
|
||||
<p><b><u><center><Font Color="white">REGISTER AN ACCOUNT</Font></p></center></b></u>
|
||||
<tr>
|
||||
<td><Font Color="#FFFFFF"><b>Account Name</b></Font></td>
|
||||
<td><input type="text" name="useraccountname"/></td>
|
||||
</tr><tr>
|
||||
<td><Font Color="#FFFFFF"><b>Password</b></Font></td>
|
||||
<td><input type="password" name="realpassword"/></td>
|
||||
</tr><tr>
|
||||
<td><Font Color="#FFFFFF"><b>Confirm Password</b></Font></td>
|
||||
<td><input type="password" name="confirmpassword"/></td>
|
||||
</tr><tr>
|
||||
<td><Font Color="#FFFFFF"><b>Access Level</b></Font></td>
|
||||
<td><select name="accesslevel">
|
||||
<option value="standard">Standard</option>
|
||||
</select></td>
|
||||
</tr>
|
||||
<tr><td></td><td>
|
||||
<input type="hidden" name="action" value="create"/>
|
||||
<input type="submit" onclick="return BothFieldsIdenticalCaseSensitive();" value="Submit"/>
|
||||
</td></tr>
|
||||
</center>
|
||||
</form>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
41
html/auth.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
include 'includes/db_connect.php';
|
||||
|
||||
function getUserByEmailAndPassword($username, $password) {
|
||||
global $mysqli;
|
||||
$result = $mysqli->query("SELECT * FROM user_account WHERE username = '$username'") or die(mysql_error());
|
||||
$no_of_rows = $result->num_rows;
|
||||
if ($no_of_rows > 0) {
|
||||
$result = $result->fetch_array();
|
||||
$salt = $result['password_salt'];
|
||||
$stored_hash = $result['password_hash'];
|
||||
$hashtest = checkhashSSHA($salt, $password);
|
||||
if ($hashtest == $stored_hash) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function checkhashSSHA($salt, $password) {
|
||||
$hash = base64_encode(sha1($password . $salt, true) . $salt);
|
||||
return $hash;
|
||||
}
|
||||
|
||||
$username = $mysqli->real_escape_string($_POST['user_name']);
|
||||
$password = $mysqli->real_escape_string($_POST['user_password']);
|
||||
$user = getUserByEmailAndPassword($username, $password);
|
||||
if ($user != false) {
|
||||
if($user['accesslevel'] == "banned") {
|
||||
$response['message'] = "Account banned";
|
||||
} else {
|
||||
$response['message'] = "success";
|
||||
}
|
||||
}
|
||||
else {
|
||||
$response['message'] = "Account does not exist or password was incorrect";
|
||||
}
|
||||
echo json_encode($response);
|
||||
?>
|
||||
38
html/create_database_table.sql
Normal file
@@ -0,0 +1,38 @@
|
||||
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||
SET time_zone = "+00:00";
|
||||
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8mb4 */;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `user_account`
|
||||
--
|
||||
|
||||
CREATE TABLE `user_account` (
|
||||
`user_id` int(11) NOT NULL,
|
||||
`accesslevel` varchar(255) NOT NULL,
|
||||
`username` varchar(255) NOT NULL,
|
||||
`password_salt` varchar(255) NOT NULL,
|
||||
`password_hash` varchar(255) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Indexes for table `user_account`
|
||||
--
|
||||
ALTER TABLE `user_account`
|
||||
ADD UNIQUE KEY `user_id` (`user_id`),
|
||||
ADD UNIQUE KEY `username` (`username`);
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT for table `user_account`
|
||||
--
|
||||
ALTER TABLE `user_account`
|
||||
MODIFY `user_id` int(11) NOT NULL AUTO_INCREMENT;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
7
html/forums/admin/backups/.htaccess
Normal 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>
|
||||
8
html/forums/admin/backups/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
1068
html/forums/admin/inc/class_form.php
Normal file
1230
html/forums/admin/inc/class_page.php
Normal file
291
html/forums/admin/inc/class_table.php
Normal 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;
|
||||
}
|
||||
}
|
||||
803
html/forums/admin/inc/functions.php
Normal file
@@ -0,0 +1,803 @@
|
||||
<?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("&", "&", $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\">« {$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} »</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>";
|
||||
}
|
||||
1602
html/forums/admin/inc/functions_themes.php
Normal file
674
html/forums/admin/inc/functions_view_manager.php
Normal 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}&action=views",
|
||||
'description' => $lang->views_desc
|
||||
);
|
||||
|
||||
$sub_tabs['create_view'] = array(
|
||||
'title' => $lang->create_new_view,
|
||||
'link' => "{$base_url}&action=views&do=add",
|
||||
'description' => $lang->create_new_view_desc
|
||||
);
|
||||
|
||||
$page->add_breadcrumb_item($lang->view_manager, 'index.php?module=user-users&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(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."&action=views&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}\">• {$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}\">• {$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(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."&action=views&do=edit&vid={$admin_view['vid']}", "post");
|
||||
|
||||
$sub_tabs = array();
|
||||
$sub_tabs['edit_view'] = array(
|
||||
'title' => $lang->edit_view,
|
||||
'link' => $base_url."&action=views&do=edit&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(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}\">• {$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}\">• {$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."&action=views&do=delete&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}&action=views&do=edit&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}&action=views&do=edit&vid={$view['vid']}");
|
||||
if($view['vid'] != $default_view)
|
||||
{
|
||||
$popup->add_item($lang->set_as_default, "{$base_url}&action=views&do=set_default&vid={$view['vid']}");
|
||||
}
|
||||
|
||||
if($views > 1 && $view['vid'] != 1)
|
||||
{
|
||||
$popup->add_item($lang->delete_view, "{$base_url}&action=views&do=delete&vid={$view['vid']}&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];
|
||||
}
|
||||
8
html/forums/admin/inc/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
822
html/forums/admin/index.php
Normal 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);
|
||||
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);
|
||||
|
||||
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'];
|
||||
}
|
||||
|
||||
// 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']);
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// Do not have a valid Admin user, throw back to login page.
|
||||
if(!isset($mybb->user['uid']) || $logged_out == true)
|
||||
{
|
||||
if($logged_out == true)
|
||||
{
|
||||
$page->show_login($lang->success_logged_out);
|
||||
}
|
||||
elseif($fail_check == 1)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
$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'],
|
||||
)
|
||||
);
|
||||
|
||||
$page->show_lockedout();
|
||||
}
|
||||
|
||||
// Still here? Show a custom login page
|
||||
$page->show_login($lang->my2fa_failed, "error");
|
||||
}
|
||||
}
|
||||
|
||||
// Show our 2FA page
|
||||
if(!empty($admin_options['authsecret']) && $admin_session['authenticated'] != 1)
|
||||
{
|
||||
$page->show_2fa();
|
||||
}
|
||||
|
||||
$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;
|
||||
|
||||
23
html/forums/admin/jscripts/admincp.js
Normal 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.submit();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
$(function()
|
||||
{
|
||||
AdminCP.init();
|
||||
});
|
||||
19
html/forums/admin/jscripts/codemirror/LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (C) 2014 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.
|
||||
32
html/forums/admin/jscripts/codemirror/addon/dialog/dialog-mybb.css
vendored
Normal 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%;
|
||||
}
|
||||
32
html/forums/admin/jscripts/codemirror/addon/dialog/dialog.css
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
.CodeMirror-dialog {
|
||||
position: absolute;
|
||||
left: 0; right: 0;
|
||||
background: white;
|
||||
z-index: 15;
|
||||
padding: .1em .8em;
|
||||
overflow: hidden;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.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%;
|
||||
}
|
||||
155
html/forums/admin/jscripts/codemirror/addon/dialog/dialog.js
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
// 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) {
|
||||
if (options.value) {
|
||||
inp.value = options.value;
|
||||
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);
|
||||
|
||||
inp.focus();
|
||||
} 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;
|
||||
});
|
||||
});
|
||||
8
html/forums/admin/jscripts/codemirror/addon/dialog/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
105
html/forums/admin/jscripts/codemirror/addon/fold/brace-fold.js
vendored
Normal 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 startCh, 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 start = start.line, has = hasImport(start), prev;
|
||||
if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 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(start, 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 start = start.line, has = hasInclude(start);
|
||||
if (has == null || hasInclude(start - 1) != null) return null;
|
||||
for (var end = start;;) {
|
||||
var next = hasInclude(end + 1);
|
||||
if (next == null) break;
|
||||
++end;
|
||||
}
|
||||
return {from: CodeMirror.Pos(start, has + 1),
|
||||
to: cm.clipPos(CodeMirror.Pos(end))};
|
||||
});
|
||||
|
||||
});
|
||||
57
html/forums/admin/jscripts/codemirror/addon/fold/comment-fold.js
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
// 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)))) {
|
||||
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)};
|
||||
});
|
||||
|
||||
});
|
||||
149
html/forums/admin/jscripts/codemirror/addon/fold/foldcode.js
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
// 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: true,
|
||||
__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";
|
||||
}
|
||||
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
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
20
html/forums/admin/jscripts/codemirror/addon/fold/foldgutter.css
vendored
Normal 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";
|
||||
}
|
||||
136
html/forums/admin/jscripts/codemirror/addon/fold/foldgutter.js
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
// 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", updateInViewport);
|
||||
}
|
||||
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", updateInViewport);
|
||||
}
|
||||
});
|
||||
|
||||
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.findMarksAt(Pos(line));
|
||||
for (var i = 0; i < marks.length; ++i)
|
||||
if (marks[i].__isFold && marks[i].find().from.line == line) return true;
|
||||
}
|
||||
|
||||
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 opts = cm.state.foldGutter.options;
|
||||
if (gutter != opts.gutter) return;
|
||||
cm.foldCode(Pos(line, 0), opts.rangeFinder);
|
||||
}
|
||||
|
||||
function onChange(cm) {
|
||||
var state = cm.state.foldGutter, opts = cm.state.foldGutter.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, opts = cm.state.foldGutter.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, line = from.line;
|
||||
if (line >= state.from && line < state.to)
|
||||
updateFoldInfo(cm, line, line + 1);
|
||||
}
|
||||
});
|
||||
44
html/forums/admin/jscripts/codemirror/addon/fold/indent-fold.js
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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", "indent", function(cm, start) {
|
||||
var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line);
|
||||
if (!/\S/.test(firstLine)) return;
|
||||
var getIndent = function(line) {
|
||||
return CodeMirror.countColumn(line, null, tabSize);
|
||||
};
|
||||
var myIndent = getIndent(firstLine);
|
||||
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 curLine = cm.getLine(i);
|
||||
var curIndent = getIndent(curLine);
|
||||
if (curIndent > myIndent) {
|
||||
// Lines with a greater indent are considered part of the block.
|
||||
lastLineInFold = i;
|
||||
} else if (!/\S/.test(curLine)) {
|
||||
// Empty lines might be breaks within the block we're trying to fold.
|
||||
} else {
|
||||
// A non-empty line at an indent equal to or less than ours marks the
|
||||
// start of another block.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastLineInFold) return {
|
||||
from: CodeMirror.Pos(start.line, firstLine.length),
|
||||
to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
8
html/forums/admin/jscripts/codemirror/addon/fold/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
49
html/forums/admin/jscripts/codemirror/addon/fold/markdown-fold.js
vendored
Normal 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)
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
182
html/forums/admin/jscripts/codemirror/addon/fold/xml-fold.js
vendored
Normal 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 ? range.from : cm.firstLine();
|
||||
this.max = range ? range.to - 1 : 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 start = Pos(iter.line, iter.ch);
|
||||
var close = findMatchingClose(iter, openTag[2]);
|
||||
return close && {from: start, to: close.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) {
|
||||
var iter = new Iter(cm, pos.line, pos.ch, range);
|
||||
for (;;) {
|
||||
var open = findMatchingOpen(iter);
|
||||
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);
|
||||
};
|
||||
});
|
||||
8
html/forums/admin/jscripts/codemirror/addon/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
8
html/forums/admin/jscripts/codemirror/addon/search/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
128
html/forums/admin/jscripts/codemirror/addon/search/match-highlighter.js
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
// 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.
|
||||
|
||||
(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 DEFAULT_MIN_CHARS = 2;
|
||||
var DEFAULT_TOKEN_STYLE = "matchhighlight";
|
||||
var DEFAULT_DELAY = 100;
|
||||
var DEFAULT_WORDS_ONLY = false;
|
||||
|
||||
function State(options) {
|
||||
if (typeof options == "object") {
|
||||
this.minChars = options.minChars;
|
||||
this.style = options.style;
|
||||
this.showToken = options.showToken;
|
||||
this.delay = options.delay;
|
||||
this.wordsOnly = options.wordsOnly;
|
||||
}
|
||||
if (this.style == null) this.style = DEFAULT_TOKEN_STYLE;
|
||||
if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS;
|
||||
if (this.delay == null) this.delay = DEFAULT_DELAY;
|
||||
if (this.wordsOnly == null) this.wordsOnly = DEFAULT_WORDS_ONLY;
|
||||
this.overlay = this.timeout = null;
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
var over = cm.state.matchHighlighter.overlay;
|
||||
if (over) cm.removeOverlay(over);
|
||||
clearTimeout(cm.state.matchHighlighter.timeout);
|
||||
cm.state.matchHighlighter = null;
|
||||
cm.off("cursorActivity", cursorActivity);
|
||||
}
|
||||
if (val) {
|
||||
cm.state.matchHighlighter = new State(val);
|
||||
highlightMatches(cm);
|
||||
cm.on("cursorActivity", cursorActivity);
|
||||
}
|
||||
});
|
||||
|
||||
function cursorActivity(cm) {
|
||||
var state = cm.state.matchHighlighter;
|
||||
clearTimeout(state.timeout);
|
||||
state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay);
|
||||
}
|
||||
|
||||
function highlightMatches(cm) {
|
||||
cm.operation(function() {
|
||||
var state = cm.state.matchHighlighter;
|
||||
if (state.overlay) {
|
||||
cm.removeOverlay(state.overlay);
|
||||
state.overlay = null;
|
||||
}
|
||||
if (!cm.somethingSelected() && state.showToken) {
|
||||
var re = state.showToken === true ? /[\w$]/ : state.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)
|
||||
cm.addOverlay(state.overlay = makeOverlay(line.slice(start, end), re, state.style));
|
||||
return;
|
||||
}
|
||||
var from = cm.getCursor("from"), to = cm.getCursor("to");
|
||||
if (from.line != to.line) return;
|
||||
if (state.wordsOnly && !isWord(cm, from, to)) return;
|
||||
var selection = cm.getRange(from, to).replace(/^\s+|\s+$/g, "");
|
||||
if (selection.length >= state.minChars)
|
||||
cm.addOverlay(state.overlay = makeOverlay(selection, false, state.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();
|
||||
}};
|
||||
}
|
||||
});
|
||||
8
html/forums/admin/jscripts/codemirror/addon/search/matchesonscrollbar.css
vendored
Normal 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;
|
||||
}
|
||||
90
html/forums/admin/jscripts/codemirror/addon/search/matchesonscrollbar.js
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
// 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, className) {
|
||||
return new SearchAnnotation(this, query, caseFold, className);
|
||||
});
|
||||
|
||||
function SearchAnnotation(cm, query, caseFold, className) {
|
||||
this.cm = cm;
|
||||
this.annotation = cm.annotateScrollbar(className || "CodeMirror-search-match");
|
||||
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);
|
||||
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 > MAX_MATCHES) 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();
|
||||
};
|
||||
});
|
||||
164
html/forums/admin/jscripts/codemirror/addon/search/search.js
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
// 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;
|
||||
return "searching";
|
||||
} else if (match) {
|
||||
stream.pos = match.index;
|
||||
} else {
|
||||
stream.skipToEnd();
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
function SearchState() {
|
||||
this.posFrom = this.posTo = 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, queryCaseInsensitive(query));
|
||||
}
|
||||
function dialog(cm, text, shortText, deflt, f) {
|
||||
if (cm.openDialog) cm.openDialog(text, f, {value: deflt});
|
||||
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 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
|
||||
}
|
||||
if (typeof query == "string" ? query == "" : query.test(""))
|
||||
query = /x^/;
|
||||
return query;
|
||||
}
|
||||
var queryDialog =
|
||||
'Search: <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 doSearch(cm, rev) {
|
||||
var state = getSearchState(cm);
|
||||
if (state.query) return findNext(cm, rev);
|
||||
dialog(cm, queryDialog, "Search for:", cm.getSelection(), function(query) {
|
||||
cm.operation(function() {
|
||||
if (!query || state.query) return;
|
||||
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));
|
||||
}
|
||||
state.posFrom = state.posTo = cm.getCursor();
|
||||
findNext(cm, rev);
|
||||
});
|
||||
});
|
||||
}
|
||||
function findNext(cm, rev) {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()});
|
||||
state.posFrom = cursor.from(); state.posTo = cursor.to();
|
||||
});}
|
||||
function clearSearch(cm) {cm.operation(function() {
|
||||
var state = getSearchState(cm);
|
||||
if (!state.query) return;
|
||||
state.query = null;
|
||||
cm.removeOverlay(state.overlay);
|
||||
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
|
||||
});}
|
||||
|
||||
var replaceQueryDialog =
|
||||
'Replace: <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 = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
|
||||
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
|
||||
function replace(cm, all) {
|
||||
if (cm.getOption("readOnly")) return;
|
||||
dialog(cm, replaceQueryDialog, "Replace:", cm.getSelection(), function(query) {
|
||||
if (!query) return;
|
||||
query = parseQuery(query);
|
||||
dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
|
||||
if (all) {
|
||||
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);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
clearSearch(cm);
|
||||
var cursor = getSearchCursor(cm, query, cm.getCursor());
|
||||
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]);
|
||||
};
|
||||
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.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);};
|
||||
});
|
||||
189
html/forums/admin/jscripts/codemirror/addon/search/searchcursor.js
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
// 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 SearchCursor(doc, query, pos, caseFold) {
|
||||
this.atOccurrence = false; this.doc = doc;
|
||||
if (caseFold == null && typeof query == "string") caseFold = false;
|
||||
|
||||
pos = pos ? doc.clipPos(pos) : Pos(0, 0);
|
||||
this.pos = {from: pos, to: pos};
|
||||
|
||||
// The matches method is filled in based on the type of query.
|
||||
// It takes a position and a direction, and returns an object
|
||||
// describing the next occurrence of the query, or null if no
|
||||
// more matches were found.
|
||||
if (typeof query != "string") { // Regexp match
|
||||
if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g");
|
||||
this.matches = function(reverse, pos) {
|
||||
if (reverse) {
|
||||
query.lastIndex = 0;
|
||||
var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start;
|
||||
for (;;) {
|
||||
query.lastIndex = cutOff;
|
||||
var newMatch = query.exec(line);
|
||||
if (!newMatch) break;
|
||||
match = newMatch;
|
||||
start = match.index;
|
||||
cutOff = match.index + (match[0].length || 1);
|
||||
if (cutOff == line.length) break;
|
||||
}
|
||||
var matchLen = (match && match[0].length) || 0;
|
||||
if (!matchLen) {
|
||||
if (start == 0 && line.length == 0) {match = undefined;}
|
||||
else if (start != doc.getLine(pos.line).length) {
|
||||
matchLen++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
query.lastIndex = pos.ch;
|
||||
var line = doc.getLine(pos.line), match = query.exec(line);
|
||||
var matchLen = (match && match[0].length) || 0;
|
||||
var start = match && match.index;
|
||||
if (start + matchLen != line.length && !matchLen) matchLen = 1;
|
||||
}
|
||||
if (match && matchLen)
|
||||
return {from: Pos(pos.line, start),
|
||||
to: Pos(pos.line, start + matchLen),
|
||||
match: match};
|
||||
};
|
||||
} else { // String query
|
||||
var origQuery = query;
|
||||
if (caseFold) query = query.toLowerCase();
|
||||
var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
|
||||
var target = query.split("\n");
|
||||
// Different methods for single-line and multi-line queries
|
||||
if (target.length == 1) {
|
||||
if (!query.length) {
|
||||
// Empty string would match anything and never progress, so
|
||||
// we define it to match nothing instead.
|
||||
this.matches = function() {};
|
||||
} else {
|
||||
this.matches = function(reverse, pos) {
|
||||
if (reverse) {
|
||||
var orig = doc.getLine(pos.line).slice(0, pos.ch), line = fold(orig);
|
||||
var match = line.lastIndexOf(query);
|
||||
if (match > -1) {
|
||||
match = adjustPos(orig, line, match);
|
||||
return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
|
||||
}
|
||||
} else {
|
||||
var orig = doc.getLine(pos.line).slice(pos.ch), line = fold(orig);
|
||||
var match = line.indexOf(query);
|
||||
if (match > -1) {
|
||||
match = adjustPos(orig, line, match) + pos.ch;
|
||||
return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
var origTarget = origQuery.split("\n");
|
||||
this.matches = function(reverse, pos) {
|
||||
var last = target.length - 1;
|
||||
if (reverse) {
|
||||
if (pos.line - (target.length - 1) < doc.firstLine()) return;
|
||||
if (fold(doc.getLine(pos.line).slice(0, origTarget[last].length)) != target[target.length - 1]) return;
|
||||
var to = Pos(pos.line, origTarget[last].length);
|
||||
for (var ln = pos.line - 1, i = last - 1; i >= 1; --i, --ln)
|
||||
if (target[i] != fold(doc.getLine(ln))) return;
|
||||
var line = doc.getLine(ln), cut = line.length - origTarget[0].length;
|
||||
if (fold(line.slice(cut)) != target[0]) return;
|
||||
return {from: Pos(ln, cut), to: to};
|
||||
} else {
|
||||
if (pos.line + (target.length - 1) > doc.lastLine()) return;
|
||||
var line = doc.getLine(pos.line), cut = line.length - origTarget[0].length;
|
||||
if (fold(line.slice(cut)) != target[0]) return;
|
||||
var from = Pos(pos.line, cut);
|
||||
for (var ln = pos.line + 1, i = 1; i < last; ++i, ++ln)
|
||||
if (target[i] != fold(doc.getLine(ln))) return;
|
||||
if (fold(doc.getLine(ln).slice(0, origTarget[last].length)) != target[last]) return;
|
||||
return {from: from, to: Pos(ln, origTarget[last].length)};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SearchCursor.prototype = {
|
||||
findNext: function() {return this.find(false);},
|
||||
findPrevious: function() {return this.find(true);},
|
||||
|
||||
find: function(reverse) {
|
||||
var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to);
|
||||
function savePosAndFail(line) {
|
||||
var pos = Pos(line, 0);
|
||||
self.pos = {from: pos, to: pos};
|
||||
self.atOccurrence = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (this.pos = this.matches(reverse, pos)) {
|
||||
this.atOccurrence = true;
|
||||
return this.pos.match || true;
|
||||
}
|
||||
if (reverse) {
|
||||
if (!pos.line) return savePosAndFail(0);
|
||||
pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length);
|
||||
}
|
||||
else {
|
||||
var maxLine = this.doc.lineCount();
|
||||
if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
|
||||
pos = Pos(pos.line + 1, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
from: function() {if (this.atOccurrence) return this.pos.from;},
|
||||
to: function() {if (this.atOccurrence) return this.pos.to;},
|
||||
|
||||
replace: function(newText) {
|
||||
if (!this.atOccurrence) return;
|
||||
var lines = CodeMirror.splitLines(newText);
|
||||
this.doc.replaceRange(lines, this.pos.from, this.pos.to);
|
||||
this.pos.to = Pos(this.pos.from.line + lines.length - 1,
|
||||
lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0));
|
||||
}
|
||||
};
|
||||
|
||||
// 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) {
|
||||
if (orig.length == folded.length) return pos;
|
||||
for (var pos1 = Math.min(pos, orig.length);;) {
|
||||
var len1 = orig.slice(0, pos1).toLowerCase().length;
|
||||
if (len1 < pos) ++pos1;
|
||||
else if (len1 > pos) --pos1;
|
||||
else return pos1;
|
||||
}
|
||||
}
|
||||
|
||||
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 = [], next;
|
||||
var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold);
|
||||
while (next = 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);
|
||||
});
|
||||
});
|
||||
8
html/forums/admin/jscripts/codemirror/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
309
html/forums/admin/jscripts/codemirror/lib/codemirror.css
vendored
Normal file
@@ -0,0 +1,309 @@
|
||||
/* BASICS */
|
||||
|
||||
.CodeMirror {
|
||||
/* Set height, width, borders, and global font properties here */
|
||||
font-family: monospace;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.CodeMirror-guttermarker { color: black; }
|
||||
.CodeMirror-guttermarker-subtle { color: #999; }
|
||||
|
||||
/* CURSOR */
|
||||
|
||||
.CodeMirror div.CodeMirror-cursor {
|
||||
border-left: 1px solid black;
|
||||
}
|
||||
/* Shown when moving in bi-directional text */
|
||||
.CodeMirror div.CodeMirror-secondarycursor {
|
||||
border-left: 1px solid silver;
|
||||
}
|
||||
.CodeMirror.cm-fat-cursor div.CodeMirror-cursor {
|
||||
width: auto;
|
||||
border: 0;
|
||||
background: #7e7;
|
||||
}
|
||||
.CodeMirror.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;
|
||||
}
|
||||
@-moz-keyframes blink {
|
||||
0% { background: #7e7; }
|
||||
50% { background: none; }
|
||||
100% { background: #7e7; }
|
||||
}
|
||||
@-webkit-keyframes blink {
|
||||
0% { background: #7e7; }
|
||||
50% { background: none; }
|
||||
100% { background: #7e7; }
|
||||
}
|
||||
@keyframes blink {
|
||||
0% { background: #7e7; }
|
||||
50% { background: none; }
|
||||
100% { background: #7e7; }
|
||||
}
|
||||
|
||||
/* Can style cursor different in overwrite (non-insert) mode */
|
||||
div.CodeMirror-overwrite div.CodeMirror-cursor {}
|
||||
|
||||
.cm-tab { display: inline-block; text-decoration: inherit; }
|
||||
|
||||
.CodeMirror-ruler {
|
||||
border-left: 1px solid #ccc;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* DEFAULT THEME */
|
||||
|
||||
.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 {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-header {color: blue;}
|
||||
.cm-s-default .cm-quote {color: #090;}
|
||||
.cm-s-default .cm-hr {color: #999;}
|
||||
.cm-s-default .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-link {text-decoration: underline;}
|
||||
.cm-strikethrough {text-decoration: line-through;}
|
||||
|
||||
.cm-s-default .cm-error {color: #f00;}
|
||||
.cm-invalidchar {color: #f00;}
|
||||
|
||||
/* 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 {
|
||||
line-height: 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.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;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
.CodeMirror-sizer {
|
||||
position: relative;
|
||||
border-right: 30px solid transparent;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
/* The fake, visible scrollbars. Used to force redraw during scrolling
|
||||
before actuall 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;
|
||||
z-index: 3;
|
||||
}
|
||||
.CodeMirror-gutter {
|
||||
white-space: normal;
|
||||
height: 100%;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
display: inline-block;
|
||||
margin-bottom: -30px;
|
||||
/* Hack to make IE7 behave */
|
||||
*zoom:1;
|
||||
*display:inline;
|
||||
}
|
||||
.CodeMirror-gutter-wrapper {
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
height: 100%;
|
||||
}
|
||||
.CodeMirror-gutter-elt {
|
||||
position: absolute;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
.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-measure {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
.CodeMirror-measure pre { position: static; }
|
||||
|
||||
.CodeMirror div.CodeMirror-cursor {
|
||||
position: absolute;
|
||||
border-right: none;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
.CodeMirror-focused div.CodeMirror-cursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-selected { background: #d9d9d9; }
|
||||
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
|
||||
.CodeMirror-crosshair { cursor: crosshair; }
|
||||
|
||||
.cm-searching {
|
||||
background: #ffa;
|
||||
background: rgba(255, 255, 0, .4);
|
||||
}
|
||||
|
||||
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
|
||||
.CodeMirror span { *vertical-align: text-bottom; }
|
||||
|
||||
/* 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; }
|
||||
8045
html/forums/admin/jscripts/codemirror/lib/codemirror.js
vendored
Normal file
8
html/forums/admin/jscripts/codemirror/lib/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
717
html/forums/admin/jscripts/codemirror/mode/css/css.js
vendored
Normal file
@@ -0,0 +1,717 @@
|
||||
// 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) {
|
||||
if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
|
||||
|
||||
var indentUnit = config.indentUnit,
|
||||
tokenHooks = parserConfig.tokenHooks,
|
||||
mediaTypes = parserConfig.mediaTypes || {},
|
||||
mediaFeatures = parserConfig.mediaFeatures || {},
|
||||
propertyKeywords = parserConfig.propertyKeywords || {},
|
||||
nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
|
||||
colorKeywords = parserConfig.colorKeywords || {},
|
||||
valueKeywords = parserConfig.valueKeywords || {},
|
||||
fontProperties = parserConfig.fontProperties || {},
|
||||
allowNested = parserConfig.allowNested;
|
||||
|
||||
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+-/)) {
|
||||
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(")) {
|
||||
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) {
|
||||
state.context = new Context(type, stream.indentation() + indentUnit, state.context);
|
||||
return type;
|
||||
}
|
||||
|
||||
function popContext(state) {
|
||||
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 (type == "@media") {
|
||||
return pushContext(state, stream, "media");
|
||||
} else if (type == "@font-face") {
|
||||
return "font_face_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}|[0-9a-fA-f]{6})$/.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 == "word") wordAsValue(stream);
|
||||
return "parens";
|
||||
};
|
||||
|
||||
states.pseudo = function(type, stream, state) {
|
||||
if (type == "word") {
|
||||
override = "variable-3";
|
||||
return state.context.type;
|
||||
}
|
||||
return pass(type, stream, state);
|
||||
};
|
||||
|
||||
states.media = function(type, stream, state) {
|
||||
if (type == "(") return pushContext(state, stream, "media_parens");
|
||||
if (type == "}") return popAndPass(type, stream, state);
|
||||
if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
|
||||
|
||||
if (type == "word") {
|
||||
var word = stream.current().toLowerCase();
|
||||
if (word == "only" || word == "not" || word == "and")
|
||||
override = "keyword";
|
||||
else if (mediaTypes.hasOwnProperty(word))
|
||||
override = "attribute";
|
||||
else if (mediaFeatures.hasOwnProperty(word))
|
||||
override = "property";
|
||||
else
|
||||
override = "error";
|
||||
}
|
||||
return state.context.type;
|
||||
};
|
||||
|
||||
states.media_parens = function(type, stream, state) {
|
||||
if (type == ")") return popContext(state);
|
||||
if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
|
||||
return states.media(type, stream, state);
|
||||
};
|
||||
|
||||
states.font_face_before = function(type, stream, state) {
|
||||
if (type == "{")
|
||||
return pushContext(state, stream, "font_face");
|
||||
return pass(type, stream, state);
|
||||
};
|
||||
|
||||
states.font_face = function(type, stream, state) {
|
||||
if (type == "}") return popContext(state);
|
||||
if (type == "word") {
|
||||
if (!fontProperties.hasOwnProperty(stream.current().toLowerCase()))
|
||||
override = "error";
|
||||
else
|
||||
override = "property";
|
||||
return "maybeprop";
|
||||
}
|
||||
return "font_face";
|
||||
};
|
||||
|
||||
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 != "variable") override = "error";
|
||||
return "interpolation";
|
||||
};
|
||||
|
||||
return {
|
||||
startState: function(base) {
|
||||
return {tokenize: null,
|
||||
state: "top",
|
||||
context: new Context("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;
|
||||
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 &&
|
||||
(ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "font_face") ||
|
||||
ch == ")" && (cx.type == "parens" || cx.type == "media_parens") ||
|
||||
ch == "{" && (cx.type == "at" || cx.type == "media"))) {
|
||||
indent = cx.indent - indentUnit;
|
||||
cx = cx.prev;
|
||||
}
|
||||
return indent;
|
||||
},
|
||||
|
||||
electricChars: "}",
|
||||
blockCommentStart: "/*",
|
||||
blockCommentEnd: "*/",
|
||||
fold: "brace"
|
||||
};
|
||||
});
|
||||
|
||||
function keySet(array) {
|
||||
var keys = {};
|
||||
for (var i = 0; i < array.length; ++i) {
|
||||
keys[array[i]] = true;
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
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"
|
||||
], mediaFeatures = keySet(mediaFeatures_);
|
||||
|
||||
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-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", "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-position", "grid-auto-rows", "grid-column", "grid-column-end",
|
||||
"grid-column-start", "grid-row", "grid-row-end", "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", "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",
|
||||
"marker-offset", "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", "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",
|
||||
"vertical-align", "visibility", "voice-balance", "voice-duration",
|
||||
"voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
|
||||
"voice-volume", "volume", "white-space", "widows", "width", "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 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", "activecaption", "afar",
|
||||
"after-white-space", "ahead", "alias", "all", "all-scroll", "alternate",
|
||||
"always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
|
||||
"arabic-indic", "armenian", "asterisks", "auto", "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", "button", "button-bevel",
|
||||
"buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian",
|
||||
"capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
|
||||
"cell", "center", "checkbox", "circle", "cjk-earthly-branch",
|
||||
"cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
|
||||
"col-resize", "collapse", "column", "compact", "condensed", "contain", "content",
|
||||
"content-box", "context-menu", "continuous", "copy", "cover", "crop",
|
||||
"cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal",
|
||||
"decimal-leading-zero", "default", "default-button", "destination-atop",
|
||||
"destination-in", "destination-out", "destination-over", "devanagari",
|
||||
"disc", "discard", "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", "ew-resize", "expanded", "extra-condensed",
|
||||
"extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "footnotes",
|
||||
"forwards", "from", "geometricPrecision", "georgian", "graytext", "groove",
|
||||
"gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew",
|
||||
"help", "hidden", "hide", "higher", "highlight", "highlighttext",
|
||||
"hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore",
|
||||
"inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
|
||||
"infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
|
||||
"inline-block", "inline-flex", "inline-table", "inset", "inside", "intrinsic", "invert",
|
||||
"italic", "justify", "kannada", "katakana", "katakana-iroha", "keep-all", "khmer",
|
||||
"landscape", "lao", "large", "larger", "left", "level", "lighter",
|
||||
"line-through", "linear", "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", "malayalam", "match",
|
||||
"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", "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", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
|
||||
"optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
|
||||
"outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
|
||||
"painted", "page", "paused", "persian", "plus-darker", "plus-lighter", "pointer",
|
||||
"polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button",
|
||||
"radio", "read-only", "read-write", "read-write-plaintext-only", "rectangle", "region",
|
||||
"relative", "repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba",
|
||||
"ridge", "right", "round", "row-resize", "rtl", "run-in", "running",
|
||||
"s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield",
|
||||
"searchfield-cancel-button", "searchfield-decoration",
|
||||
"searchfield-results-button", "searchfield-results-decoration",
|
||||
"semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
|
||||
"single", "skip-white-space", "slide", "slider-horizontal",
|
||||
"slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
|
||||
"small", "small-caps", "small-caption", "smaller", "solid", "somali",
|
||||
"source-atop", "source-in", "source-out", "source-over", "space", "square",
|
||||
"square-button", "start", "static", "status-bar", "stretch", "stroke",
|
||||
"sub", "subpixel-antialiased", "super", "sw-resize", "table",
|
||||
"table-caption", "table-cell", "table-column", "table-column-group",
|
||||
"table-footer-group", "table-header-group", "table-row", "table-row-group",
|
||||
"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",
|
||||
"transparent", "ultra-condensed", "ultra-expanded", "underline", "up",
|
||||
"upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
|
||||
"upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
|
||||
"vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
|
||||
"visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
|
||||
"window", "windowframe", "windowtext", "x-large", "x-small", "xor",
|
||||
"xx-large", "xx-small"
|
||||
], valueKeywords = keySet(valueKeywords_);
|
||||
|
||||
var fontProperties_ = [
|
||||
"font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
|
||||
"font-stretch", "font-weight", "font-style"
|
||||
], fontProperties = keySet(fontProperties_);
|
||||
|
||||
var allWords = mediaTypes_.concat(mediaFeatures_).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"];
|
||||
}
|
||||
|
||||
function tokenSGMLComment(stream, state) {
|
||||
if (stream.skipTo("-->")) {
|
||||
stream.match("-->");
|
||||
state.tokenize = null;
|
||||
} else {
|
||||
stream.skipToEnd();
|
||||
}
|
||||
return ["comment", "comment"];
|
||||
}
|
||||
|
||||
CodeMirror.defineMIME("text/css", {
|
||||
mediaTypes: mediaTypes,
|
||||
mediaFeatures: mediaFeatures,
|
||||
propertyKeywords: propertyKeywords,
|
||||
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
|
||||
colorKeywords: colorKeywords,
|
||||
valueKeywords: valueKeywords,
|
||||
fontProperties: fontProperties,
|
||||
tokenHooks: {
|
||||
"<": function(stream, state) {
|
||||
if (!stream.match("!--")) return false;
|
||||
state.tokenize = tokenSGMLComment;
|
||||
return tokenSGMLComment(stream, state);
|
||||
},
|
||||
"/": 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,
|
||||
propertyKeywords: propertyKeywords,
|
||||
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
|
||||
colorKeywords: colorKeywords,
|
||||
valueKeywords: valueKeywords,
|
||||
fontProperties: fontProperties,
|
||||
allowNested: true,
|
||||
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*\{/))
|
||||
return [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,
|
||||
propertyKeywords: propertyKeywords,
|
||||
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
|
||||
colorKeywords: colorKeywords,
|
||||
valueKeywords: valueKeywords,
|
||||
fontProperties: fontProperties,
|
||||
allowNested: true,
|
||||
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(/^(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"
|
||||
});
|
||||
|
||||
});
|
||||
8
html/forums/admin/jscripts/codemirror/mode/css/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
152
html/forums/admin/jscripts/codemirror/mode/css/less.html
vendored
Normal 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>
|
||||
51
html/forums/admin/jscripts/codemirror/mode/css/less_test.js
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
// 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]: [variable darken]([variable-2 @color], [number 10%]);",
|
||||
"}",
|
||||
"[qualifier .mixin] ([variable light]; [variable-2 @color]) {",
|
||||
" [property color]: [variable 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];",
|
||||
" }",
|
||||
" }",
|
||||
"}");
|
||||
})();
|
||||
157
html/forums/admin/jscripts/codemirror/mode/css/scss.html
vendored
Normal 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>
|
||||
110
html/forums/admin/jscripts/codemirror/mode/css/scss_test.js
vendored
Normal 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]#{[error 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]: [variable darken]([variable-2 $blue],",
|
||||
" [number 9%]);",
|
||||
"}");
|
||||
|
||||
MT('indent_vardef',
|
||||
"[variable-2 $name]:",
|
||||
" [string 'val'];",
|
||||
"[tag tag] {",
|
||||
" [tag inner] {",
|
||||
" [property margin]: [number 3px];",
|
||||
" }",
|
||||
"}");
|
||||
})();
|
||||
135
html/forums/admin/jscripts/codemirror/mode/css/test.js
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
// 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 parenthese.
|
||||
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("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("tagColorHex6",
|
||||
"[tag foo] { [property background]: [atom #ffffff]; }");
|
||||
|
||||
MT("tagColorHex4",
|
||||
"[tag foo] { [property background]: [atom&error #ffff]; }");
|
||||
|
||||
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("commentSGML",
|
||||
"[comment <!--comment-->]");
|
||||
|
||||
MT("commentSGML2",
|
||||
"[comment <!--comment]",
|
||||
"[comment -->] [tag div] {}");
|
||||
|
||||
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] [tag url]() [tag screen];");
|
||||
|
||||
MT("parens",
|
||||
"[qualifier .foo] {",
|
||||
" [property background-image]: [variable fade]([atom #000], [number 20%]);",
|
||||
" [property border-image]: [variable linear-gradient](",
|
||||
" [atom to] [atom bottom],",
|
||||
" [variable fade]([atom #000], [number 20%]) [number 0%],",
|
||||
" [variable fade]([atom #000], [number 20%]) [number 100%]",
|
||||
" );",
|
||||
"}");
|
||||
})();
|
||||
121
html/forums/admin/jscripts/codemirror/mode/htmlmixed/htmlmixed.js
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
// 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";
|
||||
|
||||
CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
|
||||
var htmlMode = CodeMirror.getMode(config, {name: "xml",
|
||||
htmlMode: true,
|
||||
multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
|
||||
multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag});
|
||||
var cssMode = CodeMirror.getMode(config, "css");
|
||||
|
||||
var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;
|
||||
scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,
|
||||
mode: CodeMirror.getMode(config, "javascript")});
|
||||
if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) {
|
||||
var conf = scriptTypesConf[i];
|
||||
scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)});
|
||||
}
|
||||
scriptTypes.push({matches: /./,
|
||||
mode: CodeMirror.getMode(config, "text/plain")});
|
||||
|
||||
function html(stream, state) {
|
||||
var tagName = state.htmlState.tagName;
|
||||
if (tagName) tagName = tagName.toLowerCase();
|
||||
var style = htmlMode.token(stream, state.htmlState);
|
||||
if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") {
|
||||
// Script block: mode to change to depends on type attribute
|
||||
var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);
|
||||
scriptType = scriptType ? scriptType[1] : "";
|
||||
if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1);
|
||||
for (var i = 0; i < scriptTypes.length; ++i) {
|
||||
var tp = scriptTypes[i];
|
||||
if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) {
|
||||
if (tp.mode) {
|
||||
state.token = script;
|
||||
state.localMode = tp.mode;
|
||||
state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, ""));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") {
|
||||
state.token = css;
|
||||
state.localMode = cssMode;
|
||||
state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
|
||||
}
|
||||
return style;
|
||||
}
|
||||
function maybeBackup(stream, pat, style) {
|
||||
var cur = stream.current();
|
||||
var close = cur.search(pat), m;
|
||||
if (close > -1) stream.backUp(cur.length - close);
|
||||
else if (m = cur.match(/<\/?$/)) {
|
||||
stream.backUp(cur.length);
|
||||
if (!stream.match(pat, false)) stream.match(cur);
|
||||
}
|
||||
return style;
|
||||
}
|
||||
function script(stream, state) {
|
||||
if (stream.match(/^<\/\s*script\s*>/i, false)) {
|
||||
state.token = html;
|
||||
state.localState = state.localMode = null;
|
||||
return null;
|
||||
}
|
||||
return maybeBackup(stream, /<\/\s*script\s*>/,
|
||||
state.localMode.token(stream, state.localState));
|
||||
}
|
||||
function css(stream, state) {
|
||||
if (stream.match(/^<\/\s*style\s*>/i, false)) {
|
||||
state.token = html;
|
||||
state.localState = state.localMode = null;
|
||||
return null;
|
||||
}
|
||||
return maybeBackup(stream, /<\/\s*style\s*>/,
|
||||
cssMode.token(stream, state.localState));
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
var state = htmlMode.startState();
|
||||
return {token: html, localMode: null, localState: null, htmlState: state};
|
||||
},
|
||||
|
||||
copyState: function(state) {
|
||||
if (state.localState)
|
||||
var local = CodeMirror.copyState(state.localMode, state.localState);
|
||||
return {token: state.token, localMode: state.localMode, localState: local,
|
||||
htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
return state.token(stream, state);
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (!state.localMode || /^\s*<\//.test(textAfter))
|
||||
return htmlMode.indent(state.htmlState, textAfter);
|
||||
else if (state.localMode.indent)
|
||||
return state.localMode.indent(state.localState, textAfter);
|
||||
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");
|
||||
|
||||
});
|
||||
8
html/forums/admin/jscripts/codemirror/mode/htmlmixed/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
8
html/forums/admin/jscripts/codemirror/mode/javascript/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
692
html/forums/admin/jscripts/codemirror/mode/javascript/javascript.js
vendored
Normal file
@@ -0,0 +1,692 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
// TODO actually recognize syntax of TypeScript constructs
|
||||
|
||||
(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": C, "delete": 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"), "module": kw("module"), "class": kw("class"), "super": kw("atom"),
|
||||
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C
|
||||
};
|
||||
|
||||
// Extend the 'normal' keywords with the TypeScript language extensions
|
||||
if (isTS) {
|
||||
var type = {type: "variable", style: "variable-3"};
|
||||
var tsKeywords = {
|
||||
// object-like things
|
||||
"interface": kw("interface"),
|
||||
"extends": kw("extends"),
|
||||
"constructor": kw("constructor"),
|
||||
|
||||
// scope modifiers
|
||||
"public": kw("public"),
|
||||
"private": kw("private"),
|
||||
"protected": kw("protected"),
|
||||
"static": kw("static"),
|
||||
|
||||
// types
|
||||
"string": type, "number": type, "bool": 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 (/\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 (state.lastType == "operator" || state.lastType == "keyword c" ||
|
||||
state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
|
||||
readRegexp(stream);
|
||||
stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
|
||||
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)) {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", "operator", stream.current());
|
||||
} else if (wordRE.test(ch)) {
|
||||
stream.eatWhile(wordRE);
|
||||
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
|
||||
return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
|
||||
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;
|
||||
|
||||
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) 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;
|
||||
if (state.context) {
|
||||
cx.marked = "def";
|
||||
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"), expression, 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"), expression, statement, poplex, maybeelse);
|
||||
}
|
||||
if (type == "function") return cont(functiondef);
|
||||
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
|
||||
if (type == "variable") return cont(pushlex("stat"), maybelabel);
|
||||
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
|
||||
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 == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex);
|
||||
if (type == "class") return cont(pushlex("form"), className, poplex);
|
||||
if (type == "export") return cont(pushlex("form"), afterExport, poplex);
|
||||
if (type == "import") return cont(pushlex("form"), afterImport, poplex);
|
||||
return pass(pushlex("stat"), expression, expect(";"), poplex);
|
||||
}
|
||||
function expression(type) {
|
||||
return expressionInner(type, false);
|
||||
}
|
||||
function expressionNoComma(type) {
|
||||
return expressionInner(type, true);
|
||||
}
|
||||
function expressionInner(type, noComma) {
|
||||
if (cx.state.fatArrowAt == cx.stream.start) {
|
||||
var body = noComma ? arrowBodyNoComma : arrowBody;
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), 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 == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
|
||||
if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, 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); }
|
||||
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)) 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);
|
||||
}
|
||||
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 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 == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property";
|
||||
if (value == "get" || value == "set") return cont(getterSetter);
|
||||
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 == "[") {
|
||||
return cont(expression, expect("]"), 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) {
|
||||
function proceed(type) {
|
||||
if (type == ",") {
|
||||
var lex = cx.state.lexical;
|
||||
if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
|
||||
return cont(what, proceed);
|
||||
}
|
||||
if (type == end) return cont();
|
||||
return cont(expect(end));
|
||||
}
|
||||
return function(type) {
|
||||
if (type == 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) {
|
||||
if (isTS && type == ":") return cont(typedef);
|
||||
}
|
||||
function typedef(type) {
|
||||
if (type == "variable"){cx.marked = "variable-3"; return cont();}
|
||||
}
|
||||
function vardef() {
|
||||
return pass(pattern, maybetype, maybeAssign, vardefCont);
|
||||
}
|
||||
function pattern(type, value) {
|
||||
if (type == "variable") { register(value); return cont(); }
|
||||
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";
|
||||
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, statement, popcontext);
|
||||
}
|
||||
function funarg(type) {
|
||||
if (type == "spread") return cont(funarg);
|
||||
return pass(pattern, maybetype);
|
||||
}
|
||||
function className(type, value) {
|
||||
if (type == "variable") {register(value); return cont(classNameAfter);}
|
||||
}
|
||||
function classNameAfter(type, value) {
|
||||
if (value == "extends") return cont(expression, classNameAfter);
|
||||
if (type == "{") return cont(pushlex("}"), classBody, poplex);
|
||||
}
|
||||
function classBody(type, value) {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property";
|
||||
if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody);
|
||||
return cont(functiondef, classBody);
|
||||
}
|
||||
if (value == "*") {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
}
|
||||
if (type == ";") return cont(classBody);
|
||||
if (type == "}") return cont();
|
||||
}
|
||||
function classGetterSetter(type) {
|
||||
if (type != "variable") return pass();
|
||||
cx.marked = "property";
|
||||
return cont();
|
||||
}
|
||||
function afterModule(type, value) {
|
||||
if (type == "string") return cont(statement);
|
||||
if (type == "variable") { register(value); return cont(maybeFrom); }
|
||||
}
|
||||
function afterExport(_type, value) {
|
||||
if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
|
||||
if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
|
||||
return pass(statement);
|
||||
}
|
||||
function afterImport(type) {
|
||||
if (type == "string") return cont();
|
||||
return pass(importSpec, maybeFrom);
|
||||
}
|
||||
function importSpec(type, value) {
|
||||
if (type == "{") return contCommasep(importSpec, "}");
|
||||
if (type == "variable") register(value);
|
||||
return cont();
|
||||
}
|
||||
function maybeFrom(_type, value) {
|
||||
if (value == "from") { cx.marked = "keyword"; return cont(expression); }
|
||||
}
|
||||
function arrayLiteral(type) {
|
||||
if (type == "]") return cont();
|
||||
return pass(expressionNoComma, maybeArrayComprehension);
|
||||
}
|
||||
function maybeArrayComprehension(type) {
|
||||
if (type == "for") return pass(comprehension, expect("]"));
|
||||
if (type == ",") return cont(commasep(maybeexpressionNoComma, "]"));
|
||||
return pass(commasep(expressionNoComma, "]"));
|
||||
}
|
||||
function comprehension(type) {
|
||||
if (type == "for") return cont(forspec, comprehension);
|
||||
if (type == "if") return cont(expression, comprehension);
|
||||
}
|
||||
|
||||
function isContinuedStatement(state, textAfter) {
|
||||
return state.lastType == "operator" || state.lastType == "," ||
|
||||
isOperatorChar.test(textAfter.charAt(0)) ||
|
||||
/[,.]/.test(textAfter.charAt(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: 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;
|
||||
// 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;
|
||||
}
|
||||
if (lexical.type == "stat" && firstChar == "}") 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",
|
||||
|
||||
helperType: jsonMode ? "json" : "javascript",
|
||||
jsonldMode: jsonldMode,
|
||||
jsonMode: jsonMode
|
||||
};
|
||||
});
|
||||
|
||||
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 });
|
||||
|
||||
});
|
||||
72
html/forums/admin/jscripts/codemirror/mode/javascript/json-ld.html
vendored
Normal 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>
|
||||
200
html/forums/admin/jscripts/codemirror/mode/javascript/test.js
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
// 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] [variable 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("class_body",
|
||||
"[keyword class] [variable Foo] {",
|
||||
" [property constructor]() {}",
|
||||
" [property sayName]() {",
|
||||
" [keyword return] [string-2 `foo${][variable foo][string-2 }oo`];",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
MT("class",
|
||||
"[keyword class] [variable Point] [keyword extends] [variable SuperThing] {",
|
||||
" [property 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("module",
|
||||
"[keyword module] [string 'foo'] {",
|
||||
" [keyword export] [keyword let] [def x] [operator =] [number 42];",
|
||||
" [keyword export] [keyword *] [keyword from] [string 'somewhere'];",
|
||||
"}");
|
||||
|
||||
MT("import",
|
||||
"[keyword function] [variable foo]() {",
|
||||
" [keyword import] [def $] [keyword from] [string 'jquery'];",
|
||||
" [keyword module] [def crypto] [keyword from] [string 'crypto'];",
|
||||
" [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];",
|
||||
"}");
|
||||
|
||||
MT("const",
|
||||
"[keyword function] [variable f]() {",
|
||||
" [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];",
|
||||
"}");
|
||||
|
||||
MT("for/of",
|
||||
"[keyword for]([keyword let] [variable of] [keyword of] [variable something]) {}");
|
||||
|
||||
MT("generator",
|
||||
"[keyword function*] [variable 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] [variable f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];");
|
||||
|
||||
MT("quotedFatArrow",
|
||||
"[keyword let] [variable 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] [variable f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];",
|
||||
"[variable c];");
|
||||
|
||||
MT("spread",
|
||||
"[keyword function] [variable f]([def a], [meta ...][def b]) {",
|
||||
" [variable something]([variable-2 a], [meta ...][variable-2 b]);",
|
||||
"}");
|
||||
|
||||
MT("comprehension",
|
||||
"[keyword function] [variable f]() {",
|
||||
" [[([variable x] [operator +] [number 1]) [keyword for] ([keyword var] [def x] [keyword in] [variable y]) [keyword if] [variable pred]([variable-2 x]) ]];",
|
||||
" ([variable u] [keyword for] ([keyword var] [def u] [keyword of] [variable generateValues]()) [keyword if] ([variable-2 u].[property color] [operator ===] [string 'blue']));",
|
||||
"}");
|
||||
|
||||
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] [variable 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] [variable i] [operator =] [number 0];",
|
||||
" [variable i] [operator <] [number 100];",
|
||||
" [variable i][operator ++])",
|
||||
" [variable doSomething]([variable i]);",
|
||||
"[keyword debugger];");
|
||||
|
||||
MT("indent_c_style",
|
||||
"[keyword function] [variable 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("multilinestring",
|
||||
"[keyword var] [variable x] [operator =] [string 'foo\\]",
|
||||
"[string bar'];");
|
||||
|
||||
MT("scary_regexp",
|
||||
"[string-2 /foo[[/]]bar/];");
|
||||
|
||||
MT("indent_strange_array",
|
||||
"[keyword var] [variable x] [operator =] [[",
|
||||
" [number 1],,",
|
||||
" [number 2],",
|
||||
"]];",
|
||||
"[number 10];");
|
||||
|
||||
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"]',
|
||||
'}');
|
||||
})();
|
||||
61
html/forums/admin/jscripts/codemirror/mode/javascript/typescript.html
vendored
Normal 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>
|
||||
8
html/forums/admin/jscripts/codemirror/mode/xml/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
51
html/forums/admin/jscripts/codemirror/mode/xml/test.js
vendored
Normal 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");
|
||||
|
||||
})();
|
||||
384
html/forums/admin/jscripts/codemirror/mode/xml/xml.js
vendored
Normal file
@@ -0,0 +1,384 @@
|
||||
// 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("xml", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit;
|
||||
var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
|
||||
var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag;
|
||||
if (multilineTagIndentPastTag == null) multilineTagIndentPastTag = true;
|
||||
|
||||
var Kludges = parserConfig.htmlMode ? {
|
||||
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
|
||||
} : {
|
||||
autoSelfClosers: {},
|
||||
implicitlyClosed: {},
|
||||
contextGrabbers: {},
|
||||
doNotIndent: {},
|
||||
allowUnquoted: false,
|
||||
allowMissing: false,
|
||||
caseFold: false
|
||||
};
|
||||
var alignCDATA = parserConfig.alignCDATA;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
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 (Kludges.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 (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
|
||||
!Kludges.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 &&
|
||||
Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName))
|
||||
popContext(state);
|
||||
if (state.context && state.context.tagName == tagName) {
|
||||
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" ||
|
||||
Kludges.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 (!Kludges.allowMissing) setStyle = "error";
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
function attrValueState(type, stream, state) {
|
||||
if (type == "string") return attrContinuedState;
|
||||
if (type == "word" && Kludges.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() {
|
||||
return {tokenize: inText,
|
||||
state: baseState,
|
||||
indented: 0,
|
||||
tagName: null, tagStart: null,
|
||||
context: null};
|
||||
},
|
||||
|
||||
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 (multilineTagIndentPastTag)
|
||||
return state.tagStart + state.tagName.length + 2;
|
||||
else
|
||||
return state.tagStart + indentUnit * multilineTagIndentFactor;
|
||||
}
|
||||
if (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 (Kludges.implicitlyClosed.hasOwnProperty(context.tagName)) {
|
||||
context = context.prev;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (tagAfter) { // Opening tag spotted
|
||||
while (context) {
|
||||
var grabbers = Kludges.contextGrabbers[context.tagName];
|
||||
if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
|
||||
context = context.prev;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (context && !context.startOfLine)
|
||||
context = context.prev;
|
||||
if (context) return context.indent + indentUnit;
|
||||
else return 0;
|
||||
},
|
||||
|
||||
electricInput: /<\/[\s\w:]+>$/,
|
||||
blockCommentStart: "<!--",
|
||||
blockCommentEnd: "-->",
|
||||
|
||||
configuration: parserConfig.htmlMode ? "html" : "xml",
|
||||
helperType: parserConfig.htmlMode ? "html" : "xml"
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/xml", "xml");
|
||||
CodeMirror.defineMIME("application/xml", "xml");
|
||||
if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
|
||||
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
|
||||
|
||||
});
|
||||
8
html/forums/admin/jscripts/codemirror/theme/index.html
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
41
html/forums/admin/jscripts/codemirror/theme/mybb.css
vendored
Normal 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;}
|
||||
8
html/forums/admin/jscripts/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 86 B |
|
After Width: | Height: | Size: 86 B |
|
After Width: | Height: | Size: 191 B |
|
After Width: | Height: | Size: 189 B |
|
After Width: | Height: | Size: 187 B |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 172 B |
|
After Width: | Height: | Size: 153 B |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
7
html/forums/admin/jscripts/jqueryui/css/redmond/jquery-ui.min.css
vendored
Normal file
5
html/forums/admin/jscripts/jqueryui/css/redmond/jquery-ui.structure.min.css
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/*! jQuery UI - v1.11.2 - 2015-01-29
|
||||
* http://jqueryui.com
|
||||
* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
|
||||
|
||||
.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}
|
||||
5
html/forums/admin/jscripts/jqueryui/css/redmond/jquery-ui.theme.min.css
vendored
Normal file
7
html/forums/admin/jscripts/jqueryui/js/jquery-ui.min.js
vendored
Normal file
57
html/forums/admin/jscripts/mycode_sandbox.js
Normal 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;
|
||||
};
|
||||
105
html/forums/admin/jscripts/peeker.js
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* 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('change', fn);
|
||||
el.click(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);
|
||||
}
|
||||
63
html/forums/admin/jscripts/quick_perm_editor.js
Normal 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);
|
||||
}
|
||||
},
|
||||
};
|
||||
74
html/forums/admin/jscripts/search.js
Normal file
@@ -0,0 +1,74 @@
|
||||
var SettingSearch = {
|
||||
|
||||
error_unknown : "",
|
||||
|
||||
init: function(settings_search, error_unknown)
|
||||
{
|
||||
this.error_unknown = error_unknown;
|
||||
|
||||
$('#settings_search').bind("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 = $.parseJSON(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);
|
||||
loadPeekers();
|
||||
$.jGrowl(lang.search_done, {theme:'jgrowl_success'});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
43
html/forums/admin/jscripts/tabs.js
Normal 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();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
87
html/forums/admin/jscripts/theme_properties.js
Normal 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).click(removeAttachmentBox);
|
||||
}
|
||||
$("#new_specific_file").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 + " <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).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();
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(init);
|
||||
|
||||
// the only public method
|
||||
return {
|
||||
setup: setup,
|
||||
};
|
||||
})();
|
||||
345
html/forums/admin/jscripts/themes.js
Normal 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(" <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;
|
||||
}
|
||||
13
html/forums/admin/jscripts/users.js
Normal file
@@ -0,0 +1,13 @@
|
||||
var Users = {
|
||||
last_value: '',
|
||||
cached_users: '',
|
||||
|
||||
init: function()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
$(function()
|
||||
{
|
||||
Users.init();
|
||||
});
|
||||
53
html/forums/admin/jscripts/view_manager.js
Normal 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();
|
||||
});
|
||||
746
html/forums/admin/modules/config/attachment_types.php
Normal file
@@ -0,0 +1,746 @@
|
||||
<?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, htmlspecialchars_uni($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&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&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'], htmlspecialchars_uni($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&action=edit&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&action=edit&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'], htmlspecialchars_uni($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&action=delete&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, htmlspecialchars_uni($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&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'] = " ";
|
||||
}
|
||||
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}";
|
||||
}
|
||||
|
||||
$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&action=edit&atid={$attachment_type['atid']}");
|
||||
$popup->add_item($phrase, "index.php?module=config-attachment_types&action=toggle_status&atid={$attachment_type['atid']}&my_post_key={$mybb->post_code}");
|
||||
$popup->add_item($lang->delete, "index.php?module=config-attachment_types&action=delete&atid={$attachment_type['atid']}&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();
|
||||
}
|
||||
|
||||
269
html/forums/admin/modules/config/badwords.php
Normal file
@@ -0,0 +1,269 @@
|
||||
<?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 = str_replace('\*', '([a-zA-Z0-9_]{1})', preg_quote($mybb->input['badword'], "#"));
|
||||
|
||||
// Don't allow certain badword replacements to be added if it would cause an infinite recursive loop.
|
||||
if(strlen($mybb->input['badword']) == strlen($mybb->input['replacement']) && preg_match("#(^|\W)".$badword."(\W|$)#i", $mybb->input['replacement']))
|
||||
{
|
||||
$errors[] = $lang->error_replacement_word_invalid;
|
||||
}
|
||||
|
||||
if(!$errors)
|
||||
{
|
||||
$new_badword = array(
|
||||
"badword" => $db->escape_string($mybb->input['badword']),
|
||||
"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']),
|
||||
"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&action=edit&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->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->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'] = '*****';
|
||||
}
|
||||
$table->construct_cell($badword['badword']);
|
||||
$table->construct_cell($badword['replacement']);
|
||||
$table->construct_cell("<a href=\"index.php?module=config-badwords&action=edit&bid={$badword['bid']}\">{$lang->edit}</a>", array("class" => "align_center"));
|
||||
$table->construct_cell("<a href=\"index.php?module=config-badwords&action=delete&bid={$badword['bid']}&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&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->end();
|
||||
$buttons[] = $form->generate_submit_button($lang->save_bad_word);
|
||||
$form->output_submit_wrapper($buttons);
|
||||
$form->end();
|
||||
|
||||
$page->output_footer();
|
||||
}
|
||||
|
||||
294
html/forums/admin/modules/config/banning.php
Normal file
@@ -0,0 +1,294 @@
|
||||
<?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, htmlspecialchars_uni($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'], htmlspecialchars_uni($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&action=delete&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&type=usernames",
|
||||
'description' => $lang->disallowed_usernames_desc
|
||||
);
|
||||
|
||||
$sub_tabs['emails'] = array(
|
||||
'title' => $lang->disallowed_email_addresses,
|
||||
'link' => "index.php?module=config-banning&type=emails",
|
||||
'description' => $lang->disallowed_email_addresses_desc
|
||||
);
|
||||
|
||||
$page->output_nav_tabs($sub_tabs, $mybb->input['type']);
|
||||
|
||||
if($errors)
|
||||
{
|
||||
$page->output_inline_error($errors);
|
||||
}
|
||||
|
||||
$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&action=delete&fid={$filter['fid']}&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);
|
||||
|
||||
$form = new Form("index.php?module=config-banning&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();
|
||||
|
||||
$page->output_footer();
|
||||
}
|
||||
|
||||
479
html/forums/admin/modules/config/calendars.php
Normal 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&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&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&action=edit&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&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&action=edit",
|
||||
'description' => $lang->edit_calendar_desc
|
||||
);
|
||||
|
||||
$page->output_nav_tabs($sub_tabs, 'edit_calendar');
|
||||
$form = new Form("index.php?module=config-calendars&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&action=delete&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&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&action=edit&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&action=edit&cid={$calendar['cid']}\">{$lang->edit}</a>", array("width" => 100, "class" => "align_center"));
|
||||
$table->construct_cell("<a href=\"index.php?module=config-calendars&action=permissions&cid={$calendar['cid']}\">{$lang->permissions}</a>", array("width" => 100, "class" => "align_center"));
|
||||
$table->construct_cell("<a href=\"index.php?module=config-calendars&action=delete&cid={$calendar['cid']}&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();
|
||||
}
|
||||
624
html/forums/admin/modules/config/help_documents.php
Normal 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&action=add&type=document"
|
||||
);
|
||||
|
||||
$sub_tabs['add_help_section'] = array(
|
||||
'title' => $lang->add_new_section,
|
||||
'link' => "index.php?module=config-help_documents&action=add&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&action=add&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&action=add&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&action=add&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&action=add&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&action=edit&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&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&action=edit&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&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&action=delete&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&action=delete&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&action=add&type=document"
|
||||
);
|
||||
|
||||
$sub_tabs['add_help_section'] = array(
|
||||
'title' => $lang->add_new_section,
|
||||
'link' => "index.php?module=config-help_documents&action=add&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&action=edit&sid={$section['sid']}\">{$section['name']}</a></strong><br /><small>{$section['description']}</small></div>");
|
||||
$table->construct_cell("<a href=\"index.php?module=config-help_documents&action=edit&sid={$section['sid']}\">{$lang->edit}</a>", array("class" => "align_center", "width" => '60'));
|
||||
$table->construct_cell("<a href=\"index.php?module=config-help_documents&action=delete&sid={$section['sid']}&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&action=edit&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&action=edit&hid={$doc['hid']}\">{$lang->edit}</a>", array("class" => "align_center", "width" => '60'));
|
||||
$table->construct_cell("<a href=\"index.php?module=config-help_documents&action=delete&hid={$doc['hid']}&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();
|
||||
}
|
||||
8
html/forums/admin/modules/config/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
1052
html/forums/admin/modules/config/languages.php
Normal file
2362
html/forums/admin/modules/config/mod_tools.php
Normal file
128
html/forums/admin/modules/config/module_meta.php
Normal 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);
|
||||
}
|
||||
488
html/forums/admin/modules/config/mycode.php
Normal 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, htmlspecialchars_uni($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&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&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> <strong>$1</strong>', $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'], htmlspecialchars_uni($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&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&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> <strong>$1</strong>', $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'], htmlspecialchars_uni($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&action=delete&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&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&action=edit&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&action=edit&cid={$mycode['cid']}");
|
||||
$popup->add_item($phrase, "index.php?module=config-mycode&action=toggle_status&cid={$mycode['cid']}&my_post_key={$mybb->post_code}");
|
||||
$popup->add_item($lang->delete_mycode, "index.php?module=config-mycode&action=delete&cid={$mycode['cid']}&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;
|
||||
}
|
||||
715
html/forums/admin/modules/config/plugins.php
Normal 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&action=check",
|
||||
'description' => $lang->plugin_updates_desc
|
||||
);
|
||||
|
||||
$sub_tabs['browse_plugins'] = array(
|
||||
'title' => $lang->browse_plugins,
|
||||
'link' => "index.php?module=config-plugins&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\">{$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&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.submit(function()
|
||||
{
|
||||
var search = $(\"#search_keywords\");
|
||||
if(search.val() == '' || search.val() == '{$lang->search_for_plugins}')
|
||||
{
|
||||
search.focus();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
var search = $(\"#search_keywords\");
|
||||
search.focus(function()
|
||||
{
|
||||
var searched_focus = $(this);
|
||||
if(searched_focus.val() == '{$lang->search_for_plugins}')
|
||||
{
|
||||
searched_focus.removeClass(\"search_default\");
|
||||
searched_focus.val(\"\");
|
||||
}
|
||||
});
|
||||
|
||||
search.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\">{$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\">{$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&action=browse{$keywords}&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");
|
||||
}
|
||||
|
||||
$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\">{$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&action=check",
|
||||
'description' => $lang->plugin_updates_desc
|
||||
);
|
||||
|
||||
$sub_tabs['browse_plugins'] = array(
|
||||
'title' => $lang->browse_plugins,
|
||||
'link' => "index.php?module=config-plugins&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&action=check",
|
||||
'description' => $lang->plugin_updates_desc
|
||||
);
|
||||
|
||||
$sub_tabs['browse_plugins'] = array(
|
||||
'title' => $lang->browse_plugins,
|
||||
'link' => "index.php?module=config-plugins&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&action=activate&plugin={$plugininfo['codename']}&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&action=deactivate&plugin={$plugininfo['codename']}&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&action=deactivate&uninstall=1&plugin={$plugininfo['codename']}&my_post_key={$mybb->post_code}\">{$lang->uninstall}</a>", array("class" => "align_center", "width" => 150));
|
||||
}
|
||||
else
|
||||
{
|
||||
$table->construct_cell(" ", 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&action=activate&plugin={$plugininfo['codename']}&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&action=deactivate&uninstall=1&plugin={$plugininfo['codename']}&my_post_key={$mybb->post_code}\">{$lang->uninstall}</a>", array("class" => "align_center", "width" => 150));
|
||||
}
|
||||
else
|
||||
{
|
||||
$table->construct_cell(" ", array("class" => "align_center", "width" => 150));
|
||||
}
|
||||
}
|
||||
}
|
||||
$table->construct_row();
|
||||
}
|
||||
}
|
||||