Merge branch 'dev' into perms
This commit is contained in:
commit
de4f9d68bd
41
CHANGELOG
41
CHANGELOG
@ -1,3 +1,44 @@
|
||||
Hubzilla 1.10
|
||||
Wiki:
|
||||
Lots of enhanced functionality, usability improvements, and bugfixes from v1.8
|
||||
Turned into an optional feature (default on) but disabled in UNO
|
||||
Sync:
|
||||
Items are now relocated (links patched) when syncing to clones
|
||||
Access Tokens:
|
||||
New feature - allows members to create access controlled guest logins and create/share 'dropbox' style links to protected resources.
|
||||
UI:
|
||||
Use icons instead of iconic text constructs
|
||||
Only request geolocation permission when creating a post, not on page load
|
||||
provide 'redeliver' option on Delivery Report page for when things really stuff up
|
||||
CalDAV/CardDAV management pages with heaps of functionality
|
||||
Lib:
|
||||
z_fetch_url() updated to accept different request methods and request bodies
|
||||
item_store(), item_store_update() now return the stored items
|
||||
vcard microformat changes to remain spec compliant
|
||||
microformat meta tags added to post/comments
|
||||
AbConfig API changed to use channel_id rather than channel_hash, which was overly complicated to use
|
||||
SuperCurl class added to provide a framework for re-use of obscure CURL options
|
||||
Allow absolute links to CSS/JS files on CDN
|
||||
Add Let'sEncrypt intermediate cert to lib in case you forget to install it on the server
|
||||
Update fullcalendar and jquery (3.1) libs
|
||||
Update sabre/dav to 3.2.0
|
||||
Change content export from a month/year system to begin/end
|
||||
Use streaming I/O for delivering large photos
|
||||
Allow multiple App description files in a single plugin directory
|
||||
optimise a couple of troublesome/inefficient SQL queries
|
||||
avoid sending clone sync packets to dead sites
|
||||
Resolved Issues:
|
||||
channel home page not providing content to clients with javascript disabled
|
||||
Replace '@' obfuscation with html entity rather than the unicode look-alike
|
||||
xchan_query() failing to detect duplicates, resulting in inefficient queries
|
||||
issues with 'use existing photo' for profile photo
|
||||
layout editor "list all layouts" returned empty
|
||||
oembed - better detect video file URLs so they aren't loaded into memory.
|
||||
handcrafted bbcode tables could end up with way too much whitespace due to CRLF translation
|
||||
refresh permissions whitescreen in 1.8
|
||||
force immediate profile photo update on local site
|
||||
regression: 'save bookmarks' post action missing
|
||||
|
||||
Hubzilla 1.8
|
||||
Administration:
|
||||
Cleanup and resolve some edge cases with addon repository manager
|
||||
|
12
README.md
12
README.md
@ -47,4 +47,16 @@ Possible website applications include
|
||||
<em><a href="https://github.com/redmatrix/hubzilla/blob/master/install/INSTALL.txt">Installing Hubzilla</a></em>
|
||||
</p>
|
||||
|
||||
**Who Are We and What Are Our Principles?**
|
||||
|
||||
The Hubzilla community is powered by passionate volunteers creating an open source **commons** of decentralised services which are highly integrated and can rival the feature set of centralised providers. We are open to sponsorship and donations to cover expenses and compensate for our time and energy, however the project core is basically non-profit and is not designed for the purpose of commercial gain or exploitation.
|
||||
|
||||
Some sites may include monetisation strategies such as subscriptions and *freemium* models where members pay for resources they consume beyond a basic level. The project community supports such monetisation initiatives (nobody should be forced to pay "out of pocket" to provide a service to others), but we maintain the **commons** to provide open and free access of the software to all.
|
||||
|
||||
The software is not designed for data collection of its members or providing advertising. We don't have a need or desire for these things and feel that software built around these goals is poorly designed and represents compromised principles and ethics.
|
||||
|
||||
As a project, we are inclusive of all beliefs and cultures and do what we are able to provide an environment that is free from hostility and harrassment. Whether or not we succeed in this endaevour requires constant vigilance and help from all members of the community, working together to build an inter-networking tool with amazing potential.
|
||||
|
||||
|
||||
|
||||
[](https://travis-ci.org/redmatrix/hubzilla)
|
||||
|
@ -62,6 +62,15 @@ class Cron {
|
||||
}
|
||||
|
||||
|
||||
// delete expired access tokens
|
||||
|
||||
q("delete from atoken where atoken_expires != '%s' && atoken_expires < %s",
|
||||
dbesc(NULL_DATE),
|
||||
dbutcnow()
|
||||
);
|
||||
|
||||
|
||||
|
||||
// Ensure that every channel pings a directory server once a month. This way we can discover
|
||||
// channels and sites that quietly vanished and prevent the directory from accumulating stale
|
||||
// or dead entries.
|
||||
|
@ -146,13 +146,40 @@ class Acl extends \Zotlabs\Web\Controller {
|
||||
if(local_channel()) {
|
||||
if($extra_channels_sql != '')
|
||||
$extra_channels_sql = " OR (abook_channel IN ($extra_channels_sql)) and abook_hidden = 0 ";
|
||||
|
||||
$r2 = null;
|
||||
|
||||
$r1 = q("select * from atoken where atoken_uid = %d",
|
||||
intval(local_channel())
|
||||
);
|
||||
if($r1) {
|
||||
require_once('include/security.php');
|
||||
$r2 = array();
|
||||
foreach($r1 as $rr) {
|
||||
$x = atoken_xchan($rr);
|
||||
$r2[] = [
|
||||
'id' => 'a' . $rr['atoken_id'] ,
|
||||
'hash' => $x['xchan_hash'],
|
||||
'name' => $x['xchan_name'],
|
||||
'micro' => $x['xchan_photo_m'],
|
||||
'url' => z_root(),
|
||||
'nick' => $x['xchan_addr'],
|
||||
'abook_their_perms' => 0,
|
||||
'abook_flags' => 0,
|
||||
'abook_self' => 0
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, xchan_pubforum, abook_flags, abook_self
|
||||
FROM abook left join xchan on abook_xchan = xchan_hash
|
||||
WHERE (abook_channel = %d $extra_channels_sql) AND abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc" ,
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
if($r2)
|
||||
$r = array_merge($r2,$r);
|
||||
|
||||
}
|
||||
else { // Visitors
|
||||
$r = q("SELECT xchan_hash as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self
|
||||
|
@ -13,6 +13,9 @@ use \Zotlabs\Storage;
|
||||
// composer autoloader for SabreDAV
|
||||
require_once('vendor/autoload.php');
|
||||
|
||||
require_once('include/attach.php');
|
||||
|
||||
|
||||
/**
|
||||
* @brief Fires up the SabreDAV server.
|
||||
*
|
||||
|
@ -14,6 +14,7 @@ use \Zotlabs\Storage;
|
||||
// composer autoloader for SabreDAV
|
||||
require_once('vendor/autoload.php');
|
||||
|
||||
require_once('include/attach.php');
|
||||
|
||||
/**
|
||||
* @brief Fires up the SabreDAV server.
|
||||
|
@ -159,7 +159,7 @@ function embedphotos_widget_album($args) {
|
||||
'$upload' => array(t('Upload'), z_root() . '/photos/' . \App::$profile['channel_address'] . '/upload/' . bin2hex($album)),
|
||||
'$order' => false,
|
||||
'$upload_form' => $upload_form,
|
||||
'$usage' => $usage_message
|
||||
'$no_fullscreen_btn' => true
|
||||
));
|
||||
|
||||
return $o;
|
||||
|
@ -28,6 +28,19 @@ class Home extends \Zotlabs\Web\Controller {
|
||||
|
||||
goaway($dest);
|
||||
}
|
||||
|
||||
if(remote_channel() && (! $splash) && $_SESSION['atoken']) {
|
||||
$r = q("select * from atoken where atoken_id = %d",
|
||||
intval($_SESSION['atoken'])
|
||||
);
|
||||
if($r) {
|
||||
$x = channelx_by_n($r[0]['atoken_uid']);
|
||||
if($x) {
|
||||
goaway(z_root() . '/channel/' . $x['channel_address']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(get_account_id() && ! $splash) {
|
||||
goaway(z_root() . '/new_channel');
|
||||
|
@ -1,17 +1,31 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
|
||||
require_once('include/security.php');
|
||||
|
||||
class Lockview extends \Zotlabs\Web\Controller {
|
||||
|
||||
function get() {
|
||||
|
||||
$atokens = array();
|
||||
|
||||
if(local_channel()) {
|
||||
$at = q("select * from atoken where atoken_uid = %d",
|
||||
intval(local_channel())
|
||||
);
|
||||
if($at) {
|
||||
foreach($at as $t) {
|
||||
$atokens[] = atoken_xchan($t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$type = ((argc() > 1) ? argv(1) : 0);
|
||||
if (is_numeric($type)) {
|
||||
$item_id = intval($type);
|
||||
$type='item';
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$item_id = ((argc() > 2) ? intval(argv(2)) : 0);
|
||||
}
|
||||
|
||||
@ -98,6 +112,13 @@ class Lockview extends \Zotlabs\Web\Controller {
|
||||
if($r)
|
||||
foreach($r as $rr)
|
||||
$l[] = '<li>' . $rr['xchan_name'] . '</li>';
|
||||
if($atokens) {
|
||||
foreach($atokens as $at) {
|
||||
if(in_array("'" . $at['xchan_hash'] . "'",$allowed_users)) {
|
||||
$l[] = '<li>' . $at['xchan_name'] . '</li>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(count($deny_groups)) {
|
||||
$r = q("SELECT gname FROM `groups` WHERE hash IN ( " . implode(', ', $deny_groups) . " )");
|
||||
@ -110,6 +131,16 @@ class Lockview extends \Zotlabs\Web\Controller {
|
||||
if($r)
|
||||
foreach($r as $rr)
|
||||
$l[] = '<li><strike>' . $rr['xchan_name'] . '</strike></li>';
|
||||
|
||||
if($atokens) {
|
||||
foreach($atokens as $at) {
|
||||
if(in_array("'" . $at['xchan_hash'] . "'",$deny_users)) {
|
||||
$l[] = '<li><strike>' . $at['xchan_name'] . '</strike></li>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
echo $o . implode($l);
|
||||
|
@ -117,6 +117,60 @@ class Settings extends \Zotlabs\Web\Controller {
|
||||
build_sync_packet();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if((argc() > 1) && (argv(1) == 'tokens')) {
|
||||
check_form_security_token_redirectOnErr('/settings/tokens', 'settings_tokens');
|
||||
$token_errs = 0;
|
||||
if(array_key_exists('token',$_POST)) {
|
||||
$atoken_id = (($_POST['atoken_id']) ? intval($_POST['atoken_id']) : 0);
|
||||
$name = trim(escape_tags($_POST['name']));
|
||||
$token = trim($_POST['token']);
|
||||
if((! $name) || (! $token))
|
||||
$token_errs ++;
|
||||
if(trim($_POST['expires']))
|
||||
$expires = datetime_convert(date_default_timezone_get(),'UTC',$_POST['expires']);
|
||||
else
|
||||
$expires = NULL_DATE;
|
||||
$max_atokens = service_class_fetch(local_channel(),'access_tokens');
|
||||
if($max_atokens) {
|
||||
$r = q("select count(atoken_id) as total where atoken_uid = %d",
|
||||
intval(local_channel())
|
||||
);
|
||||
if($r && intval($r[0]['total']) >= $max_tokens) {
|
||||
notice( sprintf( t('This channel is limited to %d tokens'), $max_tokens) . EOL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if($token_errs) {
|
||||
notice( t('Name and Password are required.') . EOL);
|
||||
return;
|
||||
}
|
||||
if($atoken_id) {
|
||||
$r = q("update atoken set atoken_name = '%s', atoken_token = '%s' atoken_expires = '%s'
|
||||
where atoken_id = %d and atoken_uid = %d",
|
||||
dbesc($name),
|
||||
dbesc($token),
|
||||
dbesc($expires),
|
||||
intval($atoken_id),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
}
|
||||
else {
|
||||
$r = q("insert into atoken ( atoken_aid, atoken_uid, atoken_name, atoken_token, atoken_expires )
|
||||
values ( %d, %d, '%s', '%s', '%s' ) ",
|
||||
intval($channel['channel_account_id']),
|
||||
intval($channel['channel_id']),
|
||||
dbesc($name),
|
||||
dbesc($token),
|
||||
dbesc($expires)
|
||||
);
|
||||
}
|
||||
|
||||
info( t('Token saved.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -706,6 +760,53 @@ class Settings extends \Zotlabs\Web\Controller {
|
||||
));
|
||||
return $o;
|
||||
}
|
||||
|
||||
if((argc() > 1) && (argv(1) === 'tokens')) {
|
||||
$atoken = null;
|
||||
if(argc() > 2) {
|
||||
$id = argv(2);
|
||||
|
||||
$atoken = q("select * from atoken where atoken_id = %d and atoken_uid = %d",
|
||||
intval($id),
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
if($atoken)
|
||||
$atoken = $atoken[0];
|
||||
|
||||
if($atoken && argc() > 3 && argv(3) === 'drop') {
|
||||
$r = q("delete from atoken where atoken_id = %d",
|
||||
intval($id)
|
||||
);
|
||||
}
|
||||
}
|
||||
$t = q("select * from atoken where atoken_uid = %d",
|
||||
intval(local_channel())
|
||||
);
|
||||
|
||||
$desc = t('Use this form to create temporary access identifiers to share things with non-members. These identities may be used in Access Control Lists and visitors may login using these credentials to access the private content.');
|
||||
|
||||
$desc2 = t('You may also provide <em>dropbox</em> style access links to friends and associates by adding the Login Password to any specific site URL as shown. Examples:');
|
||||
|
||||
$tpl = get_markup_template("settings_tokens.tpl");
|
||||
$o .= replace_macros($tpl, array(
|
||||
'$form_security_token' => get_form_security_token("settings_tokens"),
|
||||
'$title' => t('Guest Access Tokens'),
|
||||
'$desc' => $desc,
|
||||
'$desc2' => $desc2,
|
||||
'$tokens' => $t,
|
||||
'$atoken' => $atoken,
|
||||
'$url1' => z_root() . '/channel/' . $channel['channel_address'],
|
||||
'$url2' => z_root() . '/photos/' . $channel['channel_address'],
|
||||
'$name' => array('name', t('Login Name') . ' <span class="required">*</span>', (($atoken) ? $atoken['atoken_name'] : ''),''),
|
||||
'$token'=> array('token', t('Login Password') . ' <span class="required">*</span>',(($atoken) ? $atoken['atoken_token'] : autoname(8)), ''),
|
||||
'$expires'=> array('expires', t('Expires (yyyy-mm-dd)'), (($atoken['atoken_expires'] && $atoken['atoken_expires'] != NULL_DATE) ? datetime_convert('UTC',date_default_timezone_get(),$atoken['atoken_expires']) : ''), ''),
|
||||
'$submit' => t('Submit')
|
||||
));
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -206,7 +206,6 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
require_once('include/attach.php');
|
||||
|
||||
$mimetype = z_mime_content_type($name);
|
||||
|
||||
|
@ -337,6 +337,10 @@ class File extends DAV\Node implements DAV\IFile {
|
||||
}
|
||||
}
|
||||
|
||||
if(get_pconfig($this->auth->owner_id,'system','os_delete_prohibit') && \App::$module == 'dav') {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
attach_delete($this->auth->owner_id, $this->data['hash']);
|
||||
|
||||
$ch = channelx_by_n($this->auth->owner_id);
|
||||
|
@ -59,7 +59,14 @@ class WebServer {
|
||||
\App::$query_string = strip_zids(\App::$query_string);
|
||||
if(! local_channel()) {
|
||||
$_SESSION['my_address'] = $_GET['zid'];
|
||||
zid_init($a);
|
||||
zid_init();
|
||||
}
|
||||
}
|
||||
|
||||
if((x($_GET,'zat')) && (! \App::$install)) {
|
||||
\App::$query_string = strip_zats(\App::$query_string);
|
||||
if(! local_channel()) {
|
||||
zat_init();
|
||||
}
|
||||
}
|
||||
|
||||
|
6
boot.php
6
boot.php
@ -44,10 +44,10 @@ require_once('include/account.php');
|
||||
|
||||
|
||||
define ( 'PLATFORM_NAME', 'hubzilla' );
|
||||
define ( 'STD_VERSION', '1.9' );
|
||||
define ( 'STD_VERSION', '1.11' );
|
||||
define ( 'ZOT_REVISION', '1.1' );
|
||||
|
||||
define ( 'DB_UPDATE_VERSION', 1180 );
|
||||
define ( 'DB_UPDATE_VERSION', 1181 );
|
||||
|
||||
|
||||
/**
|
||||
@ -1703,7 +1703,7 @@ function login($register = false, $form_id = 'main-login', $hiddens=false) {
|
||||
'$logout' => t('Logout'),
|
||||
'$login' => t('Login'),
|
||||
'$form_id' => $form_id,
|
||||
'$lname' => array('username', t('Email') , '', ''),
|
||||
'$lname' => array('username', t('Login/Email') , '', ''),
|
||||
'$lpassword' => array('password', t('Password'), '', ''),
|
||||
'$remember_me' => array('remember_me', t('Remember me'), '', '',array(t('No'),t('Yes'))),
|
||||
'$hiddens' => $hiddens,
|
||||
|
@ -35,3 +35,4 @@ attach_upload_limit - maximum file upload storage (bytes)
|
||||
minimum_feedcheck_minutes - lowest setting allowed for polling rss feeds
|
||||
chatrooms - maximum chatrooms
|
||||
chatters_inroom - maximum chatters per room
|
||||
access_tokens - maximum number of Guest Access Tokens per channel
|
@ -36,22 +36,33 @@ function account_verify_password($email, $pass) {
|
||||
// you have to verify the email and then go through the account approval workflow before
|
||||
// letting them login.
|
||||
|
||||
if(($email_verify) && ($register_policy == REGISTER_OPEN) && ($record['account_flags'] & ACCOUNT_UNVERIFIED))
|
||||
return null;
|
||||
// @bug there is no record here
|
||||
//if(($email_verify) && ($register_policy == REGISTER_OPEN) && ($record['account_flags'] & ACCOUNT_UNVERIFIED))
|
||||
// return null;
|
||||
|
||||
$r = q("select * from account where account_email = '%s'",
|
||||
dbesc($email)
|
||||
);
|
||||
if(! ($r && count($r)))
|
||||
return null;
|
||||
if($r) {
|
||||
|
||||
foreach($r as $record) {
|
||||
if(($record['account_flags'] == ACCOUNT_OK)
|
||||
&& (hash('whirlpool', $record['account_salt'] . $pass) === $record['account_password'])) {
|
||||
logger('password verified for ' . $email);
|
||||
return $record;
|
||||
foreach($r as $record) {
|
||||
if(($record['account_flags'] == ACCOUNT_OK)
|
||||
&& (hash('whirlpool', $record['account_salt'] . $pass) === $record['account_password'])) {
|
||||
logger('password verified for ' . $email);
|
||||
return $record;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$x = q("select * from atoken where atoken_name = '%s' and atoken_token = '%s' limit 1",
|
||||
dbesc($email),
|
||||
dbesc($pass)
|
||||
);
|
||||
if($x) {
|
||||
atoken_login($x[0]);
|
||||
return $x[0];
|
||||
}
|
||||
|
||||
$error = 'password failed for ' . $email;
|
||||
logger($error);
|
||||
|
||||
@ -123,10 +134,18 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) &&
|
||||
authenticate_success($x[0], true, true);
|
||||
}
|
||||
}
|
||||
|
||||
$r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where xchan_hash = '%s' limit 1",
|
||||
dbesc($_SESSION['visitor_id'])
|
||||
);
|
||||
if(array_key_exists('atoken',$_SESSION)) {
|
||||
$y = q("select * from atoken where atoken_id = %d limit 1",
|
||||
intval($_SESSION['atoken'])
|
||||
);
|
||||
if($y)
|
||||
$r = array(atoken_xchan($y[0]));
|
||||
}
|
||||
else {
|
||||
$r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where xchan_hash = '%s' limit 1",
|
||||
dbesc($_SESSION['visitor_id'])
|
||||
);
|
||||
}
|
||||
if($r) {
|
||||
App::set_observer($r[0]);
|
||||
}
|
||||
@ -199,20 +218,27 @@ else {
|
||||
|
||||
call_hooks('authenticate', $addon_auth);
|
||||
|
||||
$atoken = false;
|
||||
|
||||
if(($addon_auth['authenticated']) && (count($addon_auth['user_record']))) {
|
||||
$record = $addon_auth['user_record'];
|
||||
}
|
||||
else {
|
||||
$record = App::$account = account_verify_password($_POST['username'], $_POST['password']);
|
||||
$x = account_verify_password($_POST['username'], $_POST['password']);
|
||||
if(array_key_exists('atoken',$x))
|
||||
$atoken = true;
|
||||
if(! $atoken) {
|
||||
$record = App::$account = $x;
|
||||
|
||||
if(App::$account) {
|
||||
$_SESSION['account_id'] = App::$account['account_id'];
|
||||
}
|
||||
else {
|
||||
notice( t('Failed authentication') . EOL);
|
||||
}
|
||||
if(App::$account) {
|
||||
$_SESSION['account_id'] = App::$account['account_id'];
|
||||
}
|
||||
else {
|
||||
notice( t('Failed authentication') . EOL);
|
||||
}
|
||||
|
||||
logger('authenticate: ' . print_r(App::$account, true), LOGGER_ALL);
|
||||
logger('authenticate: ' . print_r(App::$account, true), LOGGER_ALL);
|
||||
}
|
||||
}
|
||||
|
||||
if((! $record) || (! count($record))) {
|
||||
@ -252,7 +278,8 @@ else {
|
||||
// if we haven't failed up this point, log them in.
|
||||
|
||||
$_SESSION['last_login_date'] = datetime_convert();
|
||||
authenticate_success($record, true, true);
|
||||
if(! $atoken)
|
||||
authenticate_success($record, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,6 +297,7 @@ else {
|
||||
* @return int|bool
|
||||
* Return channel_id from pconfig or false.
|
||||
*/
|
||||
|
||||
function match_openid($authid) {
|
||||
// Query the uid/channel_id from pconfig for a given value.
|
||||
$r = q("SELECT uid FROM pconfig WHERE cat = 'system' AND k = 'openid' AND v = '%s' LIMIT 1",
|
||||
|
@ -1310,13 +1310,12 @@ function get_my_address() {
|
||||
* If somebody arrives at our site using a zid, add their xchan to our DB if we don't have it already.
|
||||
* And if they aren't already authenticated here, attempt reverse magic auth.
|
||||
*
|
||||
* @param App &$a
|
||||
*
|
||||
* @hooks 'zid_init'
|
||||
* string 'zid' - their zid
|
||||
* string 'url' - the destination url
|
||||
*/
|
||||
function zid_init(&$a) {
|
||||
function zid_init() {
|
||||
$tmp_str = get_my_address();
|
||||
if(validate_email($tmp_str)) {
|
||||
Zotlabs\Daemon\Master::Summon(array('Gprobe',bin2hex($tmp_str)));
|
||||
@ -1342,6 +1341,28 @@ function zid_init(&$a) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* If somebody arrives at our site using a zat, authenticate them
|
||||
*
|
||||
*/
|
||||
|
||||
function zat_init() {
|
||||
if(local_channel() || remote_channel())
|
||||
return;
|
||||
|
||||
$r = q("select * from atoken where atoken_token = '%s' limit 1",
|
||||
dbesc($_REQUEST['zat'])
|
||||
);
|
||||
if($r) {
|
||||
atoken_login($r[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Adds a zid parameter to a url.
|
||||
*
|
||||
|
@ -20,8 +20,6 @@ function perm_limits_upgrade($channel) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function perm_abook_upgrade($abook) {
|
||||
set_abconfig($abook['abook_channel'],$abook['abook_xchan'],'their_perms','view_stream',intval(($abook['abook_their_perms'] & PERMS_R_STREAM)? 1 : 0));
|
||||
set_abconfig($abook['abook_channel'],$abook['abook_xchan'],'their_perms','view_profile',intval(($abook['abook_their_perms'] & PERMS_R_PROFILE)? 1 : 0));
|
||||
@ -60,4 +58,7 @@ function perm_abook_upgrade($abook) {
|
||||
set_abconfig($abook['abook_channel'],$abook['abook_xchan'],'my_perms','delegate',intval(($abook['abook_my_perms'] & PERMS_A_DELEGATE)? 1 : 0));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,6 +82,44 @@ function authenticate_success($user_record, $login_initial = false, $interactive
|
||||
/* else just return */
|
||||
}
|
||||
|
||||
function atoken_login($atoken) {
|
||||
if(! $atoken)
|
||||
return false;
|
||||
|
||||
$xchan = atoken_xchan($atoken);
|
||||
|
||||
$_SESSION['authenticated'] = 1;
|
||||
$_SESSION['visitor_id'] = $xchan['xchan_hash'];
|
||||
$_SESSION['atoken'] = $atoken['atoken_id'];
|
||||
|
||||
\App::set_observer($xchan);
|
||||
|
||||
return [ 'atoken' => true ];
|
||||
}
|
||||
|
||||
|
||||
function atoken_xchan($atoken) {
|
||||
|
||||
$c = channelx_by_n($atoken['atoken_uid']);
|
||||
if($c) {
|
||||
return [
|
||||
'xchan_hash' => substr($c['channel_hash'],0,16) . '.' . $atoken['atoken_name'],
|
||||
'xchan_name' => $atoken['atoken_name'],
|
||||
'xchan_addr' => t('guest:') . $atoken['atoken_name'] . '@' . \App::get_hostname(),
|
||||
'xchan_network' => 'unknown',
|
||||
'xchan_hidden' => 1,
|
||||
'xchan_photo_mimetype' => 'image/jpeg',
|
||||
'xchan_photo_l' => get_default_profile_photo(300),
|
||||
'xchan_photo_m' => get_default_profile_photo(80),
|
||||
'xchan_photo_s' => get_default_profile_photo(48)
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Change to another channel with current logged-in account.
|
||||
*
|
||||
|
@ -774,6 +774,10 @@ function strip_zids($s) {
|
||||
return preg_replace('/[\?&]zid=(.*?)(&|$)/ism','$2',$s);
|
||||
}
|
||||
|
||||
function strip_zats($s) {
|
||||
return preg_replace('/[\?&]zat=(.*?)(&|$)/ism','$2',$s);
|
||||
}
|
||||
|
||||
|
||||
// quick and dirty quoted_printable encoding
|
||||
|
||||
|
@ -609,6 +609,15 @@ function widget_settings_menu($arr) {
|
||||
'selected' => ((argv(1) === 'oauth') ? 'active' : ''),
|
||||
);
|
||||
|
||||
if(! UNO) {
|
||||
$tabs[] = array(
|
||||
'label' => t('Guest Access Tokens'),
|
||||
'url' => z_root() . '/settings/tokens',
|
||||
'selected' => ((argv(1) === 'tokens') ? 'active' : ''),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if($role === false || $role === 'custom') {
|
||||
$tabs[] = array(
|
||||
'label' => t('Connection Default Permissions'),
|
||||
|
@ -141,6 +141,23 @@ CREATE TABLE IF NOT EXISTS `app` (
|
||||
KEY `app_edited` (`app_edited`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `atoken` (
|
||||
`atoken_id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`atoken_aid` int(11) NOT NULL DEFAULT 0,
|
||||
`atoken_uid` int(11) NOT NULL DEFAULT 0,
|
||||
`atoken_name` char(255) NOT NULL DEFAULT '',
|
||||
`atoken_token` char(255) NOT NULL DEFAULT '',
|
||||
`atoken_expires` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
PRIMARY KEY (`atoken_id`),
|
||||
KEY `atoken_aid` (`atoken_aid`),
|
||||
KEY `atoken_uid` (`atoken_uid`),
|
||||
KEY `atoken_uid_2` (`atoken_uid`),
|
||||
KEY `atoken_name` (`atoken_name`),
|
||||
KEY `atoken_token` (`atoken_token`),
|
||||
KEY `atoken_expires` (`atoken_expires`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `attach` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`aid` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
|
@ -137,6 +137,21 @@ create index "app_created" on app ("app_created");
|
||||
create index "app_edited" on app ("app_edited");
|
||||
create index "app_deleted" on app ("app_deleted");
|
||||
create index "app_system" on app ("app_system");
|
||||
|
||||
CREATE TABLE "atoken" (
|
||||
"atoken_id" serial NOT NULL,
|
||||
"atoken_aid" bigint NOT NULL DEFAULT 0,
|
||||
"atoken_uid" bigint NOT NULL DEFAULT 0,
|
||||
"atoken_name" varchar(255) NOT NULL DEFAULT '',
|
||||
"atoken_token" varchar(255) NOT NULL DEFAULT '',
|
||||
"atoken_expires" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
|
||||
PRIMARY KEY ("atoken_id"));
|
||||
create index atoken_aid on atoken (atoken_aid);
|
||||
create index atoken_uid on atoken (atoken_uid);
|
||||
create index atoken_name on atoken (atoken_name);
|
||||
create index atoken_token on atoken (atoken_token);
|
||||
create index atoken_expires on atoken (atoken_expires);
|
||||
|
||||
CREATE TABLE "attach" (
|
||||
"id" serial NOT NULL,
|
||||
"aid" bigint NOT NULL DEFAULT '0',
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
define( 'UPDATE_VERSION' , 1180 );
|
||||
define( 'UPDATE_VERSION' , 1181 );
|
||||
|
||||
/**
|
||||
*
|
||||
@ -2364,7 +2364,49 @@ function update_r1178() {
|
||||
|
||||
function update_r1179() {
|
||||
|
||||
require_once('install/perm_upgrade.php');
|
||||
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
|
||||
$r1 = q("CREATE TABLE atoken (
|
||||
atoken_id serial NOT NULL,
|
||||
atoken_aid bigint NOT NULL DEFAULT 0,
|
||||
atoken_uid bigint NOT NULL DEFAULT 0,
|
||||
atoken_name varchar(255) NOT NULL DEFAULT '',
|
||||
atoken_token varchar(255) NOT NULL DEFAULT '',
|
||||
atoken_expires timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
|
||||
PRIMARY KEY (atoken_id)) ");
|
||||
$r2 = q("create index atoken_aid on atoken (atoken_aid)");
|
||||
$r3 = q("create index atoken_uid on atoken (atoken_uid)");
|
||||
$r4 = q("create index atoken_name on atoken (atoken_name)");
|
||||
$r5 = q("create index atoken_token on atoken (atoken_token)");
|
||||
$r6 = q("create index atoken_expires on atoken (atoken_expires)");
|
||||
|
||||
$r = $r1 && $r2 && $r3 && $r4 && $r5 && $r6;
|
||||
|
||||
}
|
||||
else {
|
||||
$r = q("CREATE TABLE IF NOT EXISTS `atoken` (
|
||||
`atoken_id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`atoken_aid` int(11) NOT NULL DEFAULT 0,
|
||||
`atoken_uid` int(11) NOT NULL DEFAULT 0,
|
||||
`atoken_name` char(255) NOT NULL DEFAULT '',
|
||||
`atoken_token` char(255) NOT NULL DEFAULT '',
|
||||
`atoken_expires` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
PRIMARY KEY (`atoken_id`),
|
||||
KEY `atoken_aid` (`atoken_aid`),
|
||||
KEY `atoken_uid` (`atoken_uid`),
|
||||
KEY `atoken_name` (`atoken_name`),
|
||||
KEY `atoken_token` (`atoken_token`),
|
||||
KEY `atoken_expires` (`atoken_expires`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ");
|
||||
}
|
||||
if($r)
|
||||
return UPDATE_SUCCESS;
|
||||
return UPDATE_FAILED;
|
||||
|
||||
}
|
||||
|
||||
function update_r1180() {
|
||||
|
||||
require_once('include/perm_upgrade.php');
|
||||
|
||||
$r1 = q("select * from channel where true");
|
||||
if($r1) {
|
||||
@ -2384,6 +2426,5 @@ function update_r1179() {
|
||||
if($r)
|
||||
return UPDATE_SUCCESS;
|
||||
return UPDATE_FAILED;
|
||||
}
|
||||
|
||||
|
||||
}
|
4231
util/hmessages.po
4231
util/hmessages.po
File diff suppressed because it is too large
Load Diff
@ -56,7 +56,7 @@ if($argc == 3) {
|
||||
echo "service_class $oclass\t\t\033[1m" . $argv[2] . "\033[0m\n";
|
||||
|
||||
$new = get_config('service_class', $argv[2]);
|
||||
foreach(array('photo_upload_limit','total_items','total_pages','total_identities','total_channels','total_feeds','attach_upload_limit','minimum_feedcheck_minutes','chatrooms','chatters_inroom') as $prop) {
|
||||
foreach(array('photo_upload_limit','total_items','total_pages','total_identities','total_channels','total_feeds','attach_upload_limit','minimum_feedcheck_minutes','chatrooms','chatters_inroom','access_tokens') as $prop) {
|
||||
echo $prop . str_repeat(' ',26 - strlen($prop)) . (($old && $old[$prop]) ? $old[$prop] : 'unlimited') . "\t\t\033[1m" . (($new && $new[$prop]) ? $new[$prop] : 'unlimited') . "\033[0m\n";
|
||||
}
|
||||
$r = '';
|
||||
|
1
view/css/bootstrap-red.css
vendored
1
view/css/bootstrap-red.css
vendored
@ -5,6 +5,7 @@
|
||||
nav .badge {
|
||||
position: relative;
|
||||
top: -49px;
|
||||
left: 2px;
|
||||
float: left;
|
||||
font-size: 10px;
|
||||
line-height: 20px;
|
||||
|
@ -121,7 +121,7 @@ a.wall-item-name-link {
|
||||
}
|
||||
|
||||
.wall-item-content {
|
||||
overflow: auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wall-item-content h1,
|
||||
@ -316,4 +316,4 @@ code.inline-code {
|
||||
img.smiley.emoji:hover {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
|
@ -30,5 +30,5 @@
|
||||
}
|
||||
|
||||
.directory-collapse {
|
||||
overflow: auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
@ -7,5 +7,22 @@
|
||||
}
|
||||
|
||||
.channel-menu {
|
||||
margin-top: 24px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.zat-example {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#atoken-index {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#atoken-index td:nth-child(1){
|
||||
padding: 7px 3px 7px 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.atoken-index-tool {
|
||||
padding: 7px 10px;
|
||||
}
|
||||
|
@ -1,511 +0,0 @@
|
||||
/*!
|
||||
* jQuery Migrate - v1.1.1 - 2013-02-16
|
||||
* https://github.com/jquery/jquery-migrate
|
||||
* Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
|
||||
*/
|
||||
(function( jQuery, window, undefined ) {
|
||||
// See http://bugs.jquery.com/ticket/13335
|
||||
// "use strict";
|
||||
|
||||
|
||||
var warnedAbout = {};
|
||||
|
||||
// List of warnings already given; public read only
|
||||
jQuery.migrateWarnings = [];
|
||||
|
||||
// Set to true to prevent console output; migrateWarnings still maintained
|
||||
// jQuery.migrateMute = false;
|
||||
|
||||
// Show a message on the console so devs know we're active
|
||||
if ( !jQuery.migrateMute && window.console && console.log ) {
|
||||
console.log("JQMIGRATE: Logging is active");
|
||||
}
|
||||
|
||||
// Set to false to disable traces that appear with warnings
|
||||
if ( jQuery.migrateTrace === undefined ) {
|
||||
jQuery.migrateTrace = true;
|
||||
}
|
||||
|
||||
// Forget any warnings we've already given; public
|
||||
jQuery.migrateReset = function() {
|
||||
warnedAbout = {};
|
||||
jQuery.migrateWarnings.length = 0;
|
||||
};
|
||||
|
||||
function migrateWarn( msg) {
|
||||
if ( !warnedAbout[ msg ] ) {
|
||||
warnedAbout[ msg ] = true;
|
||||
jQuery.migrateWarnings.push( msg );
|
||||
if ( window.console && console.warn && !jQuery.migrateMute ) {
|
||||
console.warn( "JQMIGRATE: " + msg );
|
||||
if ( jQuery.migrateTrace && console.trace ) {
|
||||
console.trace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function migrateWarnProp( obj, prop, value, msg ) {
|
||||
if ( Object.defineProperty ) {
|
||||
// On ES5 browsers (non-oldIE), warn if the code tries to get prop;
|
||||
// allow property to be overwritten in case some other plugin wants it
|
||||
try {
|
||||
Object.defineProperty( obj, prop, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
migrateWarn( msg );
|
||||
return value;
|
||||
},
|
||||
set: function( newValue ) {
|
||||
migrateWarn( msg );
|
||||
value = newValue;
|
||||
}
|
||||
});
|
||||
return;
|
||||
} catch( err ) {
|
||||
// IE8 is a dope about Object.defineProperty, can't warn there
|
||||
}
|
||||
}
|
||||
|
||||
// Non-ES5 (or broken) browser; just set the property
|
||||
jQuery._definePropertyBroken = true;
|
||||
obj[ prop ] = value;
|
||||
}
|
||||
|
||||
if ( document.compatMode === "BackCompat" ) {
|
||||
// jQuery has never supported or tested Quirks Mode
|
||||
migrateWarn( "jQuery is not compatible with Quirks Mode" );
|
||||
}
|
||||
|
||||
|
||||
var attrFn = jQuery( "<input/>", { size: 1 } ).attr("size") && jQuery.attrFn,
|
||||
oldAttr = jQuery.attr,
|
||||
valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||
|
||||
function() { return null; },
|
||||
valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||
|
||||
function() { return undefined; },
|
||||
rnoType = /^(?:input|button)$/i,
|
||||
rnoAttrNodeType = /^[238]$/,
|
||||
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
|
||||
ruseDefault = /^(?:checked|selected)$/i;
|
||||
|
||||
// jQuery.attrFn
|
||||
migrateWarnProp( jQuery, "attrFn", attrFn || {}, "jQuery.attrFn is deprecated" );
|
||||
|
||||
jQuery.attr = function( elem, name, value, pass ) {
|
||||
var lowerName = name.toLowerCase(),
|
||||
nType = elem && elem.nodeType;
|
||||
|
||||
if ( pass ) {
|
||||
// Since pass is used internally, we only warn for new jQuery
|
||||
// versions where there isn't a pass arg in the formal params
|
||||
if ( oldAttr.length < 4 ) {
|
||||
migrateWarn("jQuery.fn.attr( props, pass ) is deprecated");
|
||||
}
|
||||
if ( elem && !rnoAttrNodeType.test( nType ) &&
|
||||
(attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name])) ) {
|
||||
return jQuery( elem )[ name ]( value );
|
||||
}
|
||||
}
|
||||
|
||||
// Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking
|
||||
// for disconnected elements we don't warn on $( "<button>", { type: "button" } ).
|
||||
if ( name === "type" && value !== undefined && rnoType.test( elem.nodeName ) && elem.parentNode ) {
|
||||
migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8");
|
||||
}
|
||||
|
||||
// Restore boolHook for boolean property/attribute synchronization
|
||||
if ( !jQuery.attrHooks[ lowerName ] && rboolean.test( lowerName ) ) {
|
||||
jQuery.attrHooks[ lowerName ] = {
|
||||
get: function( elem, name ) {
|
||||
// Align boolean attributes with corresponding properties
|
||||
// Fall back to attribute presence where some booleans are not supported
|
||||
var attrNode,
|
||||
property = jQuery.prop( elem, name );
|
||||
return property === true || typeof property !== "boolean" &&
|
||||
( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
|
||||
|
||||
name.toLowerCase() :
|
||||
undefined;
|
||||
},
|
||||
set: function( elem, value, name ) {
|
||||
var propName;
|
||||
if ( value === false ) {
|
||||
// Remove boolean attributes when set to false
|
||||
jQuery.removeAttr( elem, name );
|
||||
} else {
|
||||
// value is true since we know at this point it's type boolean and not false
|
||||
// Set boolean attributes to the same name and set the DOM property
|
||||
propName = jQuery.propFix[ name ] || name;
|
||||
if ( propName in elem ) {
|
||||
// Only set the IDL specifically if it already exists on the element
|
||||
elem[ propName ] = true;
|
||||
}
|
||||
|
||||
elem.setAttribute( name, name.toLowerCase() );
|
||||
}
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
||||
// Warn only for attributes that can remain distinct from their properties post-1.9
|
||||
if ( ruseDefault.test( lowerName ) ) {
|
||||
migrateWarn( "jQuery.fn.attr('" + lowerName + "') may use property instead of attribute" );
|
||||
}
|
||||
}
|
||||
|
||||
return oldAttr.call( jQuery, elem, name, value );
|
||||
};
|
||||
|
||||
// attrHooks: value
|
||||
jQuery.attrHooks.value = {
|
||||
get: function( elem, name ) {
|
||||
var nodeName = ( elem.nodeName || "" ).toLowerCase();
|
||||
if ( nodeName === "button" ) {
|
||||
return valueAttrGet.apply( this, arguments );
|
||||
}
|
||||
if ( nodeName !== "input" && nodeName !== "option" ) {
|
||||
migrateWarn("jQuery.fn.attr('value') no longer gets properties");
|
||||
}
|
||||
return name in elem ?
|
||||
elem.value :
|
||||
null;
|
||||
},
|
||||
set: function( elem, value ) {
|
||||
var nodeName = ( elem.nodeName || "" ).toLowerCase();
|
||||
if ( nodeName === "button" ) {
|
||||
return valueAttrSet.apply( this, arguments );
|
||||
}
|
||||
if ( nodeName !== "input" && nodeName !== "option" ) {
|
||||
migrateWarn("jQuery.fn.attr('value', val) no longer sets properties");
|
||||
}
|
||||
// Does not return so that setAttribute is also used
|
||||
elem.value = value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var matched, browser,
|
||||
oldInit = jQuery.fn.init,
|
||||
oldParseJSON = jQuery.parseJSON,
|
||||
// Note this does NOT include the #9521 XSS fix from 1.7!
|
||||
rquickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*|#([\w\-]*))$/;
|
||||
|
||||
// $(html) "looks like html" rule change
|
||||
jQuery.fn.init = function( selector, context, rootjQuery ) {
|
||||
var match;
|
||||
|
||||
if ( selector && typeof selector === "string" && !jQuery.isPlainObject( context ) &&
|
||||
(match = rquickExpr.exec( selector )) && match[1] ) {
|
||||
// This is an HTML string according to the "old" rules; is it still?
|
||||
if ( selector.charAt( 0 ) !== "<" ) {
|
||||
migrateWarn("$(html) HTML strings must start with '<' character");
|
||||
}
|
||||
// Now process using loose rules; let pre-1.8 play too
|
||||
if ( context && context.context ) {
|
||||
// jQuery object as context; parseHTML expects a DOM object
|
||||
context = context.context;
|
||||
}
|
||||
if ( jQuery.parseHTML ) {
|
||||
return oldInit.call( this, jQuery.parseHTML( jQuery.trim(selector), context, true ),
|
||||
context, rootjQuery );
|
||||
}
|
||||
}
|
||||
return oldInit.apply( this, arguments );
|
||||
};
|
||||
jQuery.fn.init.prototype = jQuery.fn;
|
||||
|
||||
// Let $.parseJSON(falsy_value) return null
|
||||
jQuery.parseJSON = function( json ) {
|
||||
if ( !json && json !== null ) {
|
||||
migrateWarn("jQuery.parseJSON requires a valid JSON string");
|
||||
return null;
|
||||
}
|
||||
return oldParseJSON.apply( this, arguments );
|
||||
};
|
||||
|
||||
jQuery.uaMatch = function( ua ) {
|
||||
ua = ua.toLowerCase();
|
||||
|
||||
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
|
||||
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
|
||||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
|
||||
/(msie) ([\w.]+)/.exec( ua ) ||
|
||||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
|
||||
[];
|
||||
|
||||
return {
|
||||
browser: match[ 1 ] || "",
|
||||
version: match[ 2 ] || "0"
|
||||
};
|
||||
};
|
||||
|
||||
// Don't clobber any existing jQuery.browser in case it's different
|
||||
if ( !jQuery.browser ) {
|
||||
matched = jQuery.uaMatch( navigator.userAgent );
|
||||
browser = {};
|
||||
|
||||
if ( matched.browser ) {
|
||||
browser[ matched.browser ] = true;
|
||||
browser.version = matched.version;
|
||||
}
|
||||
|
||||
// Chrome is Webkit, but Webkit is also Safari.
|
||||
if ( browser.chrome ) {
|
||||
browser.webkit = true;
|
||||
} else if ( browser.webkit ) {
|
||||
browser.safari = true;
|
||||
}
|
||||
|
||||
jQuery.browser = browser;
|
||||
}
|
||||
|
||||
// Warn if the code tries to get jQuery.browser
|
||||
migrateWarnProp( jQuery, "browser", jQuery.browser, "jQuery.browser is deprecated" );
|
||||
|
||||
jQuery.sub = function() {
|
||||
function jQuerySub( selector, context ) {
|
||||
return new jQuerySub.fn.init( selector, context );
|
||||
}
|
||||
jQuery.extend( true, jQuerySub, this );
|
||||
jQuerySub.superclass = this;
|
||||
jQuerySub.fn = jQuerySub.prototype = this();
|
||||
jQuerySub.fn.constructor = jQuerySub;
|
||||
jQuerySub.sub = this.sub;
|
||||
jQuerySub.fn.init = function init( selector, context ) {
|
||||
if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
|
||||
context = jQuerySub( context );
|
||||
}
|
||||
|
||||
return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
|
||||
};
|
||||
jQuerySub.fn.init.prototype = jQuerySub.fn;
|
||||
var rootjQuerySub = jQuerySub(document);
|
||||
migrateWarn( "jQuery.sub() is deprecated" );
|
||||
return jQuerySub;
|
||||
};
|
||||
|
||||
|
||||
// Ensure that $.ajax gets the new parseJSON defined in core.js
|
||||
jQuery.ajaxSetup({
|
||||
converters: {
|
||||
"text json": jQuery.parseJSON
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var oldFnData = jQuery.fn.data;
|
||||
|
||||
jQuery.fn.data = function( name ) {
|
||||
var ret, evt,
|
||||
elem = this[0];
|
||||
|
||||
// Handles 1.7 which has this behavior and 1.8 which doesn't
|
||||
if ( elem && name === "events" && arguments.length === 1 ) {
|
||||
ret = jQuery.data( elem, name );
|
||||
evt = jQuery._data( elem, name );
|
||||
if ( ( ret === undefined || ret === evt ) && evt !== undefined ) {
|
||||
migrateWarn("Use of jQuery.fn.data('events') is deprecated");
|
||||
return evt;
|
||||
}
|
||||
}
|
||||
return oldFnData.apply( this, arguments );
|
||||
};
|
||||
|
||||
|
||||
var rscriptType = /\/(java|ecma)script/i,
|
||||
oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
|
||||
|
||||
jQuery.fn.andSelf = function() {
|
||||
migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");
|
||||
return oldSelf.apply( this, arguments );
|
||||
};
|
||||
|
||||
// Since jQuery.clean is used internally on older versions, we only shim if it's missing
|
||||
if ( !jQuery.clean ) {
|
||||
jQuery.clean = function( elems, context, fragment, scripts ) {
|
||||
// Set context per 1.8 logic
|
||||
context = context || document;
|
||||
context = !context.nodeType && context[0] || context;
|
||||
context = context.ownerDocument || context;
|
||||
|
||||
migrateWarn("jQuery.clean() is deprecated");
|
||||
|
||||
var i, elem, handleScript, jsTags,
|
||||
ret = [];
|
||||
|
||||
jQuery.merge( ret, jQuery.buildFragment( elems, context ).childNodes );
|
||||
|
||||
// Complex logic lifted directly from jQuery 1.8
|
||||
if ( fragment ) {
|
||||
// Special handling of each script element
|
||||
handleScript = function( elem ) {
|
||||
// Check if we consider it executable
|
||||
if ( !elem.type || rscriptType.test( elem.type ) ) {
|
||||
// Detach the script and store it in the scripts array (if provided) or the fragment
|
||||
// Return truthy to indicate that it has been handled
|
||||
return scripts ?
|
||||
scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
|
||||
fragment.appendChild( elem );
|
||||
}
|
||||
};
|
||||
|
||||
for ( i = 0; (elem = ret[i]) != null; i++ ) {
|
||||
// Check if we're done after handling an executable script
|
||||
if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
|
||||
// Append to fragment and handle embedded scripts
|
||||
fragment.appendChild( elem );
|
||||
if ( typeof elem.getElementsByTagName !== "undefined" ) {
|
||||
// handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
|
||||
jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
|
||||
|
||||
// Splice the scripts into ret after their former ancestor and advance our index beyond them
|
||||
ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
|
||||
i += jsTags.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
var eventAdd = jQuery.event.add,
|
||||
eventRemove = jQuery.event.remove,
|
||||
eventTrigger = jQuery.event.trigger,
|
||||
oldToggle = jQuery.fn.toggle,
|
||||
oldLive = jQuery.fn.live,
|
||||
oldDie = jQuery.fn.die,
|
||||
ajaxEvents = "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
|
||||
rajaxEvent = new RegExp( "\\b(?:" + ajaxEvents + ")\\b" ),
|
||||
rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
|
||||
hoverHack = function( events ) {
|
||||
if ( typeof( events ) !== "string" || jQuery.event.special.hover ) {
|
||||
return events;
|
||||
}
|
||||
if ( rhoverHack.test( events ) ) {
|
||||
migrateWarn("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'");
|
||||
}
|
||||
return events && events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
|
||||
};
|
||||
|
||||
// Event props removed in 1.9, put them back if needed; no practical way to warn them
|
||||
if ( jQuery.event.props && jQuery.event.props[ 0 ] !== "attrChange" ) {
|
||||
jQuery.event.props.unshift( "attrChange", "attrName", "relatedNode", "srcElement" );
|
||||
}
|
||||
|
||||
// Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7
|
||||
if ( jQuery.event.dispatch ) {
|
||||
migrateWarnProp( jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated" );
|
||||
}
|
||||
|
||||
// Support for 'hover' pseudo-event and ajax event warnings
|
||||
jQuery.event.add = function( elem, types, handler, data, selector ){
|
||||
if ( elem !== document && rajaxEvent.test( types ) ) {
|
||||
migrateWarn( "AJAX events should be attached to document: " + types );
|
||||
}
|
||||
eventAdd.call( this, elem, hoverHack( types || "" ), handler, data, selector );
|
||||
};
|
||||
jQuery.event.remove = function( elem, types, handler, selector, mappedTypes ){
|
||||
eventRemove.call( this, elem, hoverHack( types ) || "", handler, selector, mappedTypes );
|
||||
};
|
||||
|
||||
jQuery.fn.error = function() {
|
||||
var args = Array.prototype.slice.call( arguments, 0);
|
||||
migrateWarn("jQuery.fn.error() is deprecated");
|
||||
args.splice( 0, 0, "error" );
|
||||
if ( arguments.length ) {
|
||||
return this.bind.apply( this, args );
|
||||
}
|
||||
// error event should not bubble to window, although it does pre-1.7
|
||||
this.triggerHandler.apply( this, args );
|
||||
return this;
|
||||
};
|
||||
|
||||
jQuery.fn.toggle = function( fn, fn2 ) {
|
||||
|
||||
// Don't mess with animation or css toggles
|
||||
if ( !jQuery.isFunction( fn ) || !jQuery.isFunction( fn2 ) ) {
|
||||
return oldToggle.apply( this, arguments );
|
||||
}
|
||||
migrateWarn("jQuery.fn.toggle(handler, handler...) is deprecated");
|
||||
|
||||
// Save reference to arguments for access in closure
|
||||
var args = arguments,
|
||||
guid = fn.guid || jQuery.guid++,
|
||||
i = 0,
|
||||
toggler = function( event ) {
|
||||
// Figure out which function to execute
|
||||
var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
|
||||
jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
|
||||
|
||||
// Make sure that clicks stop
|
||||
event.preventDefault();
|
||||
|
||||
// and execute the function
|
||||
return args[ lastToggle ].apply( this, arguments ) || false;
|
||||
};
|
||||
|
||||
// link all the functions, so any of them can unbind this click handler
|
||||
toggler.guid = guid;
|
||||
while ( i < args.length ) {
|
||||
args[ i++ ].guid = guid;
|
||||
}
|
||||
|
||||
return this.click( toggler );
|
||||
};
|
||||
|
||||
jQuery.fn.live = function( types, data, fn ) {
|
||||
migrateWarn("jQuery.fn.live() is deprecated");
|
||||
if ( oldLive ) {
|
||||
return oldLive.apply( this, arguments );
|
||||
}
|
||||
jQuery( this.context ).on( types, this.selector, data, fn );
|
||||
return this;
|
||||
};
|
||||
|
||||
jQuery.fn.die = function( types, fn ) {
|
||||
migrateWarn("jQuery.fn.die() is deprecated");
|
||||
if ( oldDie ) {
|
||||
return oldDie.apply( this, arguments );
|
||||
}
|
||||
jQuery( this.context ).off( types, this.selector || "**", fn );
|
||||
return this;
|
||||
};
|
||||
|
||||
// Turn global events into document-triggered events
|
||||
jQuery.event.trigger = function( event, data, elem, onlyHandlers ){
|
||||
if ( !elem && !rajaxEvent.test( event ) ) {
|
||||
migrateWarn( "Global events are undocumented and deprecated" );
|
||||
}
|
||||
return eventTrigger.call( this, event, data, elem || document, onlyHandlers );
|
||||
};
|
||||
jQuery.each( ajaxEvents.split("|"),
|
||||
function( _, name ) {
|
||||
jQuery.event.special[ name ] = {
|
||||
setup: function() {
|
||||
var elem = this;
|
||||
|
||||
// The document needs no shimming; must be !== for oldIE
|
||||
if ( elem !== document ) {
|
||||
jQuery.event.add( document, name + "." + jQuery.guid, function() {
|
||||
jQuery.event.trigger( name, null, elem, true );
|
||||
});
|
||||
jQuery._data( this, name, jQuery.guid++ );
|
||||
}
|
||||
return false;
|
||||
},
|
||||
teardown: function() {
|
||||
if ( this !== document ) {
|
||||
jQuery.event.remove( document, name + "." + jQuery._data( this, name ) );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
})( jQuery, window );
|
8
view/js/jquery.js
vendored
8
view/js/jquery.js
vendored
File diff suppressed because one or more lines are too long
2
view/js/jquery.migrate-3.0.0.js
Normal file
2
view/js/jquery.migrate-3.0.0.js
Normal file
File diff suppressed because one or more lines are too long
@ -283,12 +283,13 @@ $(function() {
|
||||
/* Turn elements with one of our special rel tags into popup menus */
|
||||
/* CHANGES: let bootstrap handle popups and only do the loading here */
|
||||
|
||||
$('a[rel^=#]').click(function(e){
|
||||
|
||||
$('a[rel^="#"]').click(function(e){
|
||||
manage_popup_menu(this, e);
|
||||
return;
|
||||
});
|
||||
|
||||
$('span[rel^=#]').click(function(e){
|
||||
$('span[rel^="#"]').click(function(e){
|
||||
manage_popup_menu(this, e);
|
||||
return;
|
||||
});
|
||||
@ -639,7 +640,7 @@ function updateConvItems(mode,data) {
|
||||
var bimgcount = bimgs.length;
|
||||
|
||||
if (bimgcount) {
|
||||
bimgs.load(function() {
|
||||
bimgs.on('load',function() {
|
||||
bimgcount--;
|
||||
if (! bimgcount) {
|
||||
collapseHeight();
|
||||
@ -652,7 +653,7 @@ function updateConvItems(mode,data) {
|
||||
}
|
||||
|
||||
function collapseHeight() {
|
||||
var origContentHeight = parseInt($("#region_2").height());
|
||||
var origContentHeight = Math.ceil($("#region_2").height());
|
||||
var cDiff = 0;
|
||||
var i = 0;
|
||||
var position = $(window).scrollTop();
|
||||
@ -662,25 +663,19 @@ function collapseHeight() {
|
||||
if(orgHeight > divmore_height) {
|
||||
if(! $(this).hasClass('divmore')) {
|
||||
|
||||
//var trigger = $(window).scrollTop() < $(this).offset().top ? true : false;
|
||||
//console.log($(this).offset().top + divmore_height - $(window).scrollTop() + cDiff - ($(".divgrow-showmore").outerHeight() * i));
|
||||
|
||||
// check if we will collapse some content above the visible content and compensate the diff later
|
||||
if($(this).offset().top + divmore_height - $(window).scrollTop() + cDiff - ($(".divgrow-showmore").outerHeight() * i) < 65) {
|
||||
//$(this).css('color', 'red');
|
||||
//console.log($(this).offset().top + divmore_height + ' / ' + $(window).scrollTop());
|
||||
diff = orgHeight - divmore_height;
|
||||
cDiff = cDiff + diff;
|
||||
i++;
|
||||
}
|
||||
|
||||
//if(trigger) {
|
||||
$(this).readmore({
|
||||
speed: 0,
|
||||
heightMargin: 50,
|
||||
collapsedHeight: divmore_height,
|
||||
moreLink: '<a href="#" class="divgrow-showmore">' + aStr.divgrowmore + '</a>',
|
||||
lessLink: '<a href="#" class="divgrow-showmore">' + aStr.divgrowless + '</a>',
|
||||
moreLink: '<a href="#" class="divgrow-showmore fakelink">' + aStr.divgrowmore + '</a>',
|
||||
lessLink: '<a href="#" class="divgrow-showmore fakelink">' + aStr.divgrowless + '</a>',
|
||||
beforeToggle: function(trigger, element, expanded) {
|
||||
if(expanded) {
|
||||
if((($(element).offset().top + divmore_height) - $(window).scrollTop()) < 65 ) {
|
||||
@ -690,12 +685,11 @@ function collapseHeight() {
|
||||
}
|
||||
});
|
||||
$(this).addClass('divmore');
|
||||
//}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var collapsedContentHeight = parseInt($("#region_2").height());
|
||||
var collapsedContentHeight = Math.ceil($("#region_2").height());
|
||||
contentHeightDiff = origContentHeight - collapsedContentHeight;
|
||||
console.log('collapseHeight() - contentHeightDiff: ' + contentHeightDiff + 'px');
|
||||
|
||||
|
@ -5,6 +5,9 @@
|
||||
$(document).ready(function() {
|
||||
$('form').areYouSure({'addRemoveFieldsMarksDirty':true, 'message': aStr['leavethispage'] }); // Warn user about unsaved settings
|
||||
|
||||
$('.token-mirror').html($('#id_token').val());
|
||||
$('#id_token').keyup( function() { $('.token-mirror').html($('#id_token').val()); });
|
||||
|
||||
$("#id_permissions_role").change(function() {
|
||||
var role = $("#id_permissions_role").val();
|
||||
if(role == 'custom')
|
||||
|
@ -13,7 +13,7 @@ head_add_css('library/justifiedGallery/justifiedGallery.min.css');
|
||||
head_add_css('library/Text_Highlighter/sample.css');
|
||||
|
||||
head_add_js('jquery.js');
|
||||
//head_add_js('jquery-migrate-1.1.1.js');
|
||||
//head_add_js('jquery.migrate-3.0.0.js');
|
||||
head_add_js('library/justifiedGallery/jquery.justifiedGallery.min.js');
|
||||
head_add_js('library/sprintf.js/dist/sprintf.min.js');
|
||||
|
||||
|
@ -1416,9 +1416,6 @@ img.mail-conv-sender-photo {
|
||||
display: block;
|
||||
border-top: 1px dashed #ccc;
|
||||
text-align: center;
|
||||
font-size: $body_font_size;
|
||||
color: $link_colour;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.divgrow-showmore:hover {
|
||||
@ -1658,6 +1655,7 @@ main.fullscreen .section-content-wrapper-np {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.atoken-index-row:hover td,
|
||||
.chatroom-index-row:hover td,
|
||||
.locs-index-row:hover td,
|
||||
[id^="cloud-index-"]:hover td,
|
||||
|
@ -56,16 +56,15 @@ $(document).ready(function() {
|
||||
function makeFullScreen(full) {
|
||||
if(typeof full=='undefined' || full == true) {
|
||||
$('main').css({'transition': 'none'}).addClass('fullscreen');
|
||||
$('header, nav, aside, #tabs-collapse-1').css({'visibility': 'hidden'});
|
||||
$('#fullscreen-btn').hide();
|
||||
$('header, nav, aside, #fullscreen-btn').hide();
|
||||
$('#tabs-collapse-1').css({'visibility': 'hidden'});
|
||||
$('#inline-btn').show();
|
||||
|
||||
}
|
||||
else {
|
||||
$('main').removeClass('fullscreen');
|
||||
$('header, nav, aside, #tabs-collapse-1').css({'visibility': ''});
|
||||
$('header, nav, aside, #fullscreen-btn').show();
|
||||
$('#tabs-collapse-1').css({'visibility': ''});
|
||||
$('#inline-btn').hide();
|
||||
$('#fullscreen-btn').show();
|
||||
$('main').css({'transition': ''});
|
||||
}
|
||||
}
|
||||
|
@ -153,6 +153,18 @@ if(file_exists('view/theme/redbasic/css/style.css')) {
|
||||
|
||||
$x = file_get_contents('view/theme/redbasic/css/style.css');
|
||||
|
||||
if($narrow_navbar && file_exists('view/theme/redbasic/css/narrow_navbar.css')) {
|
||||
$x .= file_get_contents('view/theme/redbasic/css/narrow_navbar.css');
|
||||
}
|
||||
|
||||
if($align_left && file_exists('view/theme/redbasic/css/align_left.css')) {
|
||||
$x .= file_get_contents('view/theme/redbasic/css/align_left.css');
|
||||
}
|
||||
|
||||
if($schemecss) {
|
||||
$x .= $schemecss;
|
||||
}
|
||||
|
||||
$aside_width = 287;
|
||||
|
||||
// left aside and right aside are 285px + converse width
|
||||
@ -204,18 +216,6 @@ if(file_exists('view/theme/redbasic/css/style.css')) {
|
||||
|
||||
}
|
||||
|
||||
if($narrow_navbar && file_exists('view/theme/redbasic/css/narrow_navbar.css')) {
|
||||
echo file_get_contents('view/theme/redbasic/css/narrow_navbar.css');
|
||||
}
|
||||
|
||||
if($align_left && file_exists('view/theme/redbasic/css/align_left.css')) {
|
||||
echo file_get_contents('view/theme/redbasic/css/align_left.css');
|
||||
}
|
||||
|
||||
if($schemecss) {
|
||||
echo $schemecss;
|
||||
}
|
||||
|
||||
// Set the schema to the default schema in derived themes. See the documentation for creating derived themes how to override this.
|
||||
|
||||
if(local_channel() && App::$channel && App::$channel['channel_theme'] != 'redbasic')
|
||||
|
@ -11,4 +11,3 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
|
@ -1,8 +1,17 @@
|
||||
<script>
|
||||
var aside_padding_top;
|
||||
var section_padding_top;
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
aside_padding_top = parseInt($('aside').css('padding-top'));
|
||||
section_padding_top = parseInt($('section').css('padding-top'));
|
||||
|
||||
if($('#cover-photo').length && $(window).width() > 755) {
|
||||
$('.navbar-fixed-top').css('position', 'relative');
|
||||
$('aside, section').css('padding-top', 0 + 'px');
|
||||
$('main').css('margin-top', - $('nav').outerHeight(true) + 'px');
|
||||
$('aside').css('padding-top', aside_padding_top - $('nav').outerHeight() + 'px');
|
||||
$('section').css('padding-top', section_padding_top - $('nav').outerHeight() + 'px');
|
||||
$('main').css('opacity', 0);
|
||||
$('header').hide();
|
||||
}
|
||||
@ -15,9 +24,11 @@
|
||||
if($('#cover-photo').length && $(window).width() > 755 && $(window).scrollTop() >= $('#cover-photo').height()) {
|
||||
$('header').fadeIn();
|
||||
$('main').css('opacity', 1);
|
||||
$('aside, section').css('padding-top', $('nav').outerHeight(true) + 'px');
|
||||
$('aside').css('padding-top', aside_padding_top + 'px');
|
||||
$('section').css('padding-top', section_padding_top + 'px');
|
||||
$(window).scrollTop($(window).scrollTop() - $('#cover-photo').height())
|
||||
$('.navbar-fixed-top').css('position', 'fixed');
|
||||
$('main').css('margin-top', '');
|
||||
$('#cover-photo').remove();
|
||||
}
|
||||
if($('#cover-photo').length) {
|
||||
@ -28,7 +39,8 @@
|
||||
$(window).resize(function () {
|
||||
if($('#cover-photo').length && $(window).width() < 755) {
|
||||
$('main').css('opacity', 1);
|
||||
$('aside, section').css('padding-top', $('nav').outerHeight(true) + 'px');
|
||||
$('aside').css('padding-top', aside_padding_top + 'px');
|
||||
$('section').css('padding-top', section_padding_top + 'px');
|
||||
$('.navbar-fixed-top').css('position', 'fixed');
|
||||
$('#cover-photo').remove();
|
||||
}
|
||||
@ -36,7 +48,7 @@
|
||||
});
|
||||
|
||||
function slideUpCover() {
|
||||
$('html, body').animate({scrollTop: $('#cover-photo').height() + 'px'});
|
||||
$('html, body').animate({scrollTop: Math.ceil($('#cover-photo').height()) + 'px' });
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -12,8 +12,10 @@
|
||||
<button class="btn btn-xs btn-success btn-xs" title="{{$usage}}" onclick="openClose('photo-upload-form'); closeMenu('photo-album-edit-wrapper');"><i class="fa fa-arrow-circle-o-up"></i> {{$upload.0}}</button>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{if !$no_fullscreen_btn}}
|
||||
<button id="fullscreen-btn" type="button" class="btn btn-default btn-xs" onclick="makeFullScreen();"><i class="fa fa-expand"></i></button>
|
||||
<button id="inline-btn" type="button" class="btn btn-default btn-xs" onclick="makeFullScreen(false);"><i class="fa fa-compress"></i></button>
|
||||
{{/if}}
|
||||
</div>
|
||||
<h2>{{$album}}</h2>
|
||||
<div class="clear"></div>
|
||||
|
40
view/tpl/settings_tokens.tpl
Normal file
40
view/tpl/settings_tokens.tpl
Normal file
@ -0,0 +1,40 @@
|
||||
<div class="generic-content-wrapper">
|
||||
<div class="section-title-wrapper">
|
||||
<h2>{{$title}}</h2>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
<div class="section-content-tools-wrapper">
|
||||
<div class="section-content-info-wrapper">
|
||||
{{$desc}}
|
||||
</div>
|
||||
|
||||
<form action="settings/tokens" id="settings-account-form" method="post" autocomplete="off" >
|
||||
<input type='hidden' name='form_security_token' value='{{$form_security_token}}'>
|
||||
{{if $atoken}}<input type="hidden" name="atoken_id" value="{{$atoken.atoken_id}}" />{{/if}}
|
||||
{{include file="field_input.tpl" field=$name}}
|
||||
{{include file="field_input.tpl" field=$token}}
|
||||
{{include file="field_input.tpl" field=$expires}}
|
||||
<div class="settings-submit-wrapper form-group">
|
||||
<button type="submit" name="submit" class="btn btn-primary">{{$submit}}</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="descriptive-text">{{$desc2}}</div>
|
||||
<ul>
|
||||
<li>{{$url1}}<span class="zat-example">?f=&zat=<span class="token-mirror"></span></span></li>
|
||||
<li>{{$url2}}<span class="zat-example">?f=&zat=<span class="token-mirror"></span></span></li>
|
||||
</ul>
|
||||
</div>
|
||||
{{if $tokens}}
|
||||
<div class="section-content-wrapper-np">
|
||||
<table id="atoken-index">
|
||||
{{foreach $tokens as $t}}
|
||||
<tr id="atoken-index-{{$t.atoken_id}}" class="atoken-index-row">
|
||||
<td width="99%"><a href="settings/tokens/{{$t.atoken_id}}">{{$t.atoken_name}}</a></td>
|
||||
<td width="1%" class="atoken-index-tool"><i class="fa fa-trash-o drop-icons" onClick="dropItem('/settings/tokens/{{$t.atoken_id}}/drop', '#atoken-index-{{$t.atoken_id}}')"></i></td>
|
||||
</tr>
|
||||
{{/foreach}}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
Reference in New Issue
Block a user