First release,no database required,code style changes

This commit is contained in:
nipos 2018-03-11 12:07:57 +01:00
parent 6afd23142e
commit 5ccb63b8c5
136 changed files with 11598 additions and 16247 deletions

View File

@ -4,9 +4,6 @@ RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.(.+?)$
RewriteRule ^(.*)$ https://$1 [R=301,L]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Main
RewriteBase /
RewriteRule ^home/?$ / [R=301]

17
404.php Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Halcyon / ?</title>
<link rel="shortcut icon" href="/assets/images/favicon.ico">
<link rel="stylesheet" href="/assets/css/404.css" media="all">
</head>
<body>
<article>
<h1>404</h1>
<h2>Sorry, something went wrong.</h2>
</article>
</body>
</html>

View File

@ -1,10 +1,13 @@
# Halcyon for Mastodon
A Mastodon web client that looks like Twitter
>The original author of this genious piece of software was inactive for a while and then shut down his demo instance and deleted this repository. I love Halcyon, it's the thing which makes Mastodon the best social network in the world. I took the Code from the Halcyon fork of cybre.space which still works but doesn't seem to get updates, too. I uploaded it here to make the original link work again and don't link into the big nothing. I'm working on much other stuff, too, what is why I won't be very active here in the near future but I do things which are required to keep it working and if I have much more time, I already know some nice features which could come. As for now I don't have an own demo instance but the one from cybre.space works pretty good and when I changed many things, I will open an own one.
>The original author of this genius piece of software was inactive for a while and then shut down his demo instance and deleted this repository. I love Halcyon, it's the thing which makes Mastodon the best social network in the world. I took the Code from the Halcyon fork of cybre.space which still works but doesn't seem to get updates, too. I uploaded it here to make the original link work again and don't link into the big nothing. I'm working on much other stuff, too, what is why I won't be very active here in the near future but I do things which are required to keep it working and if I have much more time, I already know some nice features which could come. As for now I don't have an own demo instance but the one from cybre.space works pretty good and when I changed many things, I will open an own one.
<img src="https://halcyon.cybre.space/login/assets/images/preview0.png">
## Blog
- [Release of Version 1.0.0](http://nikisoft.myblog.de/nikisoft/art/11264555/The-first-new-Halcyon-release-is-on-Github)
## Demo
https://halcyon.cybre.space/
Please note that this demo is not owned by me and I have not control over it. Currently I'm not providing an own demo so I link to that one. That may change in future.
@ -15,48 +18,13 @@ Please note that this demo is not owned by me and I have not control over it. Cu
- No tracking, No ads.
## Requirement
- Apache
- Apache/Nginx/lighttpd
- PHP
- MySQL
- No database needed anymore!
## Setup
I didn't prepared setup script so you have to setup manually...
### PDO MySQL
After installed PHP, run this.
```bash
sudo pecl install pdo_mysql
sudo vi php.ini
```
change to this
```php.ini
extension=mysqli.so
extension=pdo_mysql.so
```
### MySQL
After installed MySQL, create a user, run this.
```sql
CREATE DATABASE DATABASE_NAME DEFAULT CHARACTER SET utf8;
CREATE TABLE DATABASE_NAME.instances(domain varchar(261), client_id varchar(64), client_secret varchar(64));
```
and make file `/config.ini` like this
```config.ini
~~~ line 3 ~~~
api_client_name = <APP NAME>
api_client_website = <APP WEBSITE LINK>
~~~ line 8 ~~~
db_host = <DATABASE HOST DOMAIN>
db_user = <DATABASE USERNAME>
db_pass = <DATABASE PASSWORD>
db_name = <DATABASE NAME>
```
Upload it, edit config.ini and have fun!
## Credits
- [Kirschn/mastodon.js](https://github.com/Kirschn/mastodon.js)
- [yks118/Mastodon-api-php](https://github.com/yks118/Mastodon-api-php)

View File

@ -1,17 +0,0 @@
# Roadmap
These plans may change if I think something else is more important or if I consider something here as not that important!
## Next version
- [x] Oauth login
- [x] Support responsive
- [ ] Add meida attachment's next/prev button
## Future
- [ ] Multi account
- [ ] Emoji picker
- [ ] Native profile edit
- [ ] Dark theme
- [ ] Translation support
- [ ] Mobile devices support
- [ ] PHP PSR4 / Autoload

132
assets/css/404.css Normal file
View File

@ -0,0 +1,132 @@
@charset "utf-8";
* {
margin: 0;
padding: 0;
font-size: 100%;
}
a {
text-decoration: none;
word-break: break-all;
color: inherit;
}
a:hover {
text-decoration: underline;
}
ul, ol {
list-style: none;
padding: 0;
margin: 0;
}
img {
vertical-align: top;
border: 0;
max-width: 100%;
max-height: 100%;
}
button {
font-size: 100%;
}
.clear {
clear: both;
}
.red {
color: red!important;
}
.invisible {
display: none!important;
}
.no-events {
pointer-events: none;
}
.disallow_select {
user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
}
.text_ellipsis {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
h1, h2, h3, h4, h5, h6 {
font-weight: normal;
line-height: 1;
margin: 0;
padding: 0;
}
blockquote, q {
quotes: none;
margin: 0;
}
blockquote * {
margin: 0;
word-break: break-all;
}
blockquote:before, blockquote:after,
q:before, q:after {
content:'';
content:none;
}
article,aside,details,figcaption,figure,
footer,header,hgroup,menu,nav,section {
display:block;
}
textarea {
width: 100%;
}
input {
max-width: 100%;
}
button, input[type="submit"], input[type="button"]{
background-color: transparent;
border: none;
cursor: pointer;
outline: none;
padding: 0;
appearance: none;
}
img.emoji {
height: 1em;
width: 1em;
margin: 0 .05em 0 .1em;
vertical-align: -0.1em;
}
.emoji_poss .auth_emoji {
display: inline-block;
height: 100%;
margin: auto;
margin-left: 4px;
}
html {
font-family : "Helvetica Neue",Helvetica,Arial,sans-serif;
font-size : 100%;
line-height : 1;
color: #333;
min-width: 100%;
min-height: 100%;
}
body {
margin: 0;
padding: 0;
min-width: 100%;
min-height: 100%;
word-wrap:break-word;
background-color: #189EFC;
}
article {
margin: auto;
padding: 24px;
}
h1 {
font-size: 248px;
text-align: center;
color: #fff;
font-weight: 600;
}
h2 {
font-size: 56px;
text-align: center;
color: #fff;
font-weight: 200;
}

2326
assets/css/style.css Normal file

File diff suppressed because it is too large Load Diff

View File

Before

Width:  |  Height:  |  Size: 361 KiB

After

Width:  |  Height:  |  Size: 361 KiB

View File

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

BIN
assets/images/mastodon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="61.076954mm" height="65.47831mm" viewBox="0 0 216.4144 232.00976"><path d="M211.80734 139.0875c-3.18125 16.36625-28.4925 34.2775-57.5625 37.74875-15.15875 1.80875-30.08375 3.47125-45.99875 2.74125-26.0275-1.1925-46.565-6.2125-46.565-6.2125 0 2.53375.15625 4.94625.46875 7.2025 3.38375 25.68625 25.47 27.225 46.39125 27.9425 21.11625.7225 39.91875-5.20625 39.91875-5.20625l.8675 19.09s-14.77 7.93125-41.08125 9.39c-14.50875.7975-32.52375-.365-53.50625-5.91875C9.23234 213.82 1.40609 165.31125.20859 116.09125c-.365-14.61375-.14-28.39375-.14-39.91875 0-50.33 32.97625-65.0825 32.97625-65.0825C49.67234 3.45375 78.20359.2425 107.86484 0h.72875c29.66125.2425 58.21125 3.45375 74.8375 11.09 0 0 32.975 14.7525 32.975 65.0825 0 0 .41375 37.13375-4.59875 62.915" fill="#3088d4"/><path d="M177.50984 80.077v60.94125h-24.14375v-59.15c0-12.46875-5.24625-18.7975-15.74-18.7975-11.6025 0-17.4175 7.5075-17.4175 22.3525v32.37625H96.20734V85.42325c0-14.845-5.81625-22.3525-17.41875-22.3525-10.49375 0-15.74 6.32875-15.74 18.7975v59.15H38.90484V80.077c0-12.455 3.17125-22.3525 9.54125-29.675 6.56875-7.3225 15.17125-11.07625 25.85-11.07625 12.355 0 21.71125 4.74875 27.8975 14.2475l6.01375 10.08125 6.015-10.08125c6.185-9.49875 15.54125-14.2475 27.8975-14.2475 10.6775 0 19.28 3.75375 25.85 11.07625 6.36875 7.3225 9.54 17.22 9.54 29.675" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 126 B

After

Width:  |  Height:  |  Size: 126 B

View File

Before

Width:  |  Height:  |  Size: 126 B

After

Width:  |  Height:  |  Size: 126 B

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,174 @@
function getLinkFromXHRHeader(xhrheaderstring) {
const re = xhrheaderstring.match(/link: <.+api\/v1\/(.+?)>; rel="(.+?)", <.+api\/v1\/(.+?)>; rel="(.+?)"/);
let di = new Object();
if(re){
di[re[2]] = re[1];
di[re[4]] = re[3];
}
return di;
}
function getRelativeURL(url, id, options) {
const array = url.split('/');
if ( array.length >= 4 ) {
if ( !options ) {
var options = ""
};
if (id) {
if (array[array.length-1].substr(0,1) === '@') {
const link= '/'+array[array.length-1]+'@'+array[2]+options+'?mid='+id+'&';
return link;
}
else {
const link= '/@'+array[array.length-1]+'@'+array[2]+options+'?mid='+id+'&';
return link;
}
}
else {
if (array[array.length-1].substr(0,1) === '@') {
const link= '/'+array[array.length-1]+'@'+array[2]+options;
return link;
} else {
const link= '/@'+array[array.length-1]+'@'+array[2]+options;
return link;
}
}
}
}
function replaceInternalLink(){
$(".h-card > a").each(function(i) {
$(this).attr('href',getRelativeURL($(this).attr('href')));
});
$(".toot_article a").each(function(i) {
const tags = $(this).attr('href').match(/https:\/\/.+..+\/tags\/(.+)\/?/);
if (tags) {
$(this).attr('href','/search?q='+tags[1]);
}
});
}
function getConversionedDate(key, value) {
if (value === null ||
value.constructor !== String ||
value.search(/^\d{4}-\d{2}-\d{2}/g) === -1)
return value;
return new Date(value);
}
function getRelativeDatetime(current_time, posted_time) {
const calendar = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var posted_time_original = posted_time,
posted_time = getConversionedDate(null, posted_time_original).getTime(),
elapsedTime = Math.ceil((current_time-posted_time)/1000);
if (elapsedTime < 60) {
const datetime ="・" + elapsedTime + "s";
return datetime;
}
else if (elapsedTime < 120) {
const datetime ="・1m";
return datetime;
}
else if (elapsedTime < (60*60)) {
const datetime ="・" + (Math.floor(elapsedTime / 60) < 10 ? " " : "") + Math.floor(elapsedTime / 60) + "m";
return datetime;
}
else if (elapsedTime < (120*60)) {
const datetime ="・1h";
return datetime;
}
else if (elapsedTime < (24*60*60)) {
const datetime ="・" + (Math.floor(elapsedTime / 3600) < 10 ? " " : "") + Math.floor(elapsedTime / 3600) + "h";
return datetime;
}
else {
const datetime ="・" + calendar[posted_time_original.getMonth()] + " " + posted_time_original.getDate();
return datetime;
}
}
function resetApp() {
current_id = Number(localStorage.getItem("current_id"));
current_instance = localStorage.getItem("current_instance");
authtoken= localStorage.getItem("current_authtoken");
api = new MastodonAPI({
instance: 'https://'+current_instance,
api_user_token: authtoken
});
api.get("accounts/verify_credentials", function(AccountObj) {
localStorage.setItem("current_display_name", AccountObj["display_name"]);
localStorage.setItem("current_acct", AccountObj["acct"]);
localStorage.setItem("current_url", getRelativeURL(AccountObj["url"],AccountObj["id"]));
localStorage.setItem("current_header", AccountObj["header"]);
localStorage.setItem("current_avatar", AccountObj["avatar"]);
localStorage.setItem("current_statuses_count", AccountObj["statuses_count"]);
localStorage.setItem("current_following_count", AccountObj["following_count"]);
localStorage.setItem("current_followers_count", AccountObj["followers_count"]);
localStorage.setItem("current_statuses_count_link", getRelativeURL(AccountObj["url"],AccountObj["id"]));
localStorage.setItem("current_following_count_link", getRelativeURL(AccountObj["url"],AccountObj["id"],'/following'));
localStorage.setItem("current_followers_count_link", getRelativeURL(AccountObj["url"],AccountObj["id"],'/followers'));
localStorage.setItem("current_favourites_link", getRelativeURL(AccountObj["url"],AccountObj["id"],'/favourites'));
current_display_name = localStorage.getItem("current_display_name");
current_acct = localStorage.getItem("current_acct");
current_url = localStorage.getItem("current_url");
current_header = localStorage.getItem("current_header");
current_avatar = localStorage.getItem("current_avatar");
current_statuses_count = localStorage.getItem("current_statuses_count");
current_following_count = localStorage.getItem("current_following_count");
current_followers_count = localStorage.getItem("current_followers_count");
current_statuses_count_link = localStorage.getItem("current_statuses_count_link");
current_following_count_link = localStorage.getItem("current_following_count_link");
current_followers_count_link = localStorage.getItem("current_followers_count_link");
current_favourites_link = localStorage.getItem("current_favourites_link");
$(".js_current_profile_displayname").text(current_display_name);
$(".js_current_profile_username").text(current_acct);
$(".js_current_profile_link").attr('href', current_url);
$(".js_current_header_image").attr('src', current_header);
$(".js_current_profile_image").attr('src', current_avatar);
$(".js_current_toots_count").text(current_statuses_count);
$(".js_current_following_count").text(current_following_count);
$(".js_current_followers_count").text(current_followers_count);
$(".current_toots_count_link").attr('href', current_statuses_count_link);
$(".current_following_count_link").attr('href', current_following_count_link);
$(".current_followers_count_link").attr('href', current_followers_count_link);
replace_emoji();
});
$.cookie("session", "true", { path: '/' });
}
function refreshApp() {
current_id = Number(localStorage.getItem("current_id"));
current_instance = localStorage.getItem("current_instance");
authtoken= localStorage.getItem("current_authtoken");
api = new MastodonAPI({
instance: "https://"+current_instance,
api_user_token: authtoken
});
current_display_name = localStorage.getItem("current_display_name");
current_acct = localStorage.getItem("current_acct");
current_url= localStorage.getItem("current_url");
current_header = localStorage.getItem("current_header");
current_avatar = localStorage.getItem("current_avatar");
current_statuses_count = localStorage.getItem("current_statuses_count");
current_following_count= localStorage.getItem("current_following_count");
current_followers_count= localStorage.getItem("current_followers_count");
current_statuses_count_link= localStorage.getItem("current_statuses_count_link");
current_following_count_link = localStorage.getItem("current_following_count_link");
current_followers_count_link = localStorage.getItem("current_followers_count_link");
current_favourites_link= localStorage.getItem("current_favourites_link");
}
function setCurrentProfile() {
$(".js_current_profile_displayname").text(current_display_name);
$(".js_current_profile_username").text(current_acct);
$(".js_current_profile_link").attr("href", current_url);
$(".js_current_header_image").attr("src", current_header);
$(".js_current_profile_image").attr("src", current_avatar);
$(".js_current_toots_count").text(current_statuses_count);
$(".js_current_following_count").text(current_following_count);
$(".js_current_followers_count").text(current_followers_count);
$(".current_toots_count_link").attr("href", current_statuses_count_link);
$(".current_following_count_link").attr("href", current_following_count_link);
$(".current_followers_count_link").attr("href", current_followers_count_link);
replace_emoji();
}
function putMessage(Message) {
$('#overlay_message').addClass('view');
$('#overlay_message section span').text(Message);
setTimeout(function(){
$("#overlay_message").removeClass("view");
},3000);
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,78 @@
/*!
* jQuery Cookie Plugin v1.4.1
* https://github.com/carhartl/jquery-cookie
*
* Copyright 2006, 2014 Klaus Hartl
* Released under the MIT license
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
}(function ($) {
var pluses = /\+/g;
function encode(s) {
return config.raw ? s : encodeURIComponent(s);
}
function decode(s) {
return config.raw ? s : decodeURIComponent(s);
}
function stringifyCookieValue(value) {
return encode(config.json ? JSON.stringify(value) : String(value));
}
function parseCookieValue(s) {
if (s.indexOf('"') === 0) {
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
}
try {
s = decodeURIComponent(s.replace(pluses, ' '));
return config.json ? JSON.parse(s) : s;
} catch(e) {}
}
function read(s, converter) {
var value = config.raw ? s : parseCookieValue(s);
return $.isFunction(converter) ? converter(value) : value;
}
var config = $.cookie = function (key, value, options) {
if (arguments.length > 1 && !$.isFunction(value)) {
options = $.extend({}, config.defaults, options);
if (typeof options.expires === 'number') {
var days = options.expires, t = options.expires = new Date();
t.setMilliseconds(t.getMilliseconds() + days * 864e+5);
}
return (document.cookie = [
encode(key), '=', stringifyCookieValue(value),
options.expires ? '; expires=' + options.expires.toUTCString() : '',
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
options.secure ? '; secure' : ''
].join(''));
}
var result = key ? undefined : {},
cookies = document.cookie ? document.cookie.split('; ') : [],
i = 0,
l = cookies.length;
for (; i < l; i++) {
var parts = cookies[i].split('='),
name = decode(parts.shift()),
cookie = parts.join('=');
if (key === name) {
result = read(cookie, value);
break;
}
if (!key && (cookie = read(cookie)) !== undefined) {
result[name] = cookie;
}
}
return result;
};
config.defaults = {};
$.removeCookie = function (key, options) {
$.cookie(key, '', $.extend({}, options, { expires: -1 }));
return !$.cookie(key);
};
}));

View File

@ -0,0 +1,207 @@
// mastodon javascript lib
// by @kirschn@pleasehug.me 2017
// no fucking copyright
// do whatever you want with it
// but please don't hurt it (and keep this header)
var MastodonAPI = function(config) {
var apiBase = config.instance + "/api/v1/";
return {
setConfig: function (key, value) {
config[key] = value;
},
getConfig: function(key) {
return config[key];
},
get: function (endpoint) {
var queryData, callback,
queryStringAppend = "?";
if (typeof arguments[1] === "function") {
queryData = {};
callback = arguments[1];
} else {
queryData = arguments[1];
callback = arguments[2];
}
for (var i in queryData) {
if (queryData.hasOwnProperty(i)) {
if (typeof queryData[i] === "string") {
queryStringAppend += queryData[i] + "&";
} else if (typeof queryData[i] === "object") {
queryStringAppend += queryData[i].name + "="+ queryData[i].data + "&";
}
}
}
$.ajax({
url: apiBase + endpoint + queryStringAppend,
type: "GET",
headers: {"Authorization": "Bearer " + config.api_user_token},
success: function(data, textStatus, xhr) {
console.log("Successful GET API request to " +apiBase+endpoint);
responce_headers = xhr.getAllResponseHeaders();
callback(data,textStatus);
},
error: function(xhr, textStatus, errorThrown) {
putMessage(`[${xhr.status}] ${xhr.responseJSON['error']}`);
if ( xhr.status === 401 ) {
location.href = "/logout"
}
}
});
},
getArray: function (endpoint) {
var queryData, callback,
queryStringAppend = "?";
if (typeof arguments[1] === "function") {
queryData = {};
callback = arguments[1];
} else {
queryData = arguments[1];
callback = arguments[2];
}
for (var i in queryData) {
if (queryData.hasOwnProperty(i)) {
if (typeof queryData[i] === "string") {
queryStringAppend += queryData[i] + "&";
} else if (typeof queryData[i] === "object") {
for ( var j in queryData[i].data ){
queryStringAppend += queryData[i].name + "[]="+ queryData[i].data[j] + "&";
}
}
}
}
$.ajax({
url: apiBase + endpoint + queryStringAppend,
type: "GET",
headers: {"Authorization": "Bearer " + config.api_user_token},
success: function(data, textStatus, xhr) {
console.log("Successful GET API request to " +apiBase+endpoint);
responce_headers = xhr.getAllResponseHeaders();
callback(data,textStatus);
},
error: function(xhr, textStatus, errorThrown) {
putMessage(`[${xhr.status}] ${xhr.responseJSON['error']}`);
if ( xhr.status === 401 ) {
location.href = "/logout"
}
}
});
},
getOther: function (domainAndEndpoint) {
var queryData, callback,
queryStringAppend = "?";
if (typeof arguments[1] === "function") {
queryData = {};
callback = arguments[1];
} else {
queryData = arguments[1];
callback = arguments[2];
}
for (var i in queryData) {
if (queryData.hasOwnProperty(i)) {
if (typeof queryData[i] === "string") {
queryStringAppend += queryData[i] + "&";
} else if (typeof queryData[i] === "object") {
queryStringAppend += queryData[i].name + "="+ queryData[i].data + "&";
}
}
}
$.ajax({
url: domainAndEndpoint + queryStringAppend,
type: "GET",
success: function(data, textStatus, xhr) {
console.log("Successful GET API request to " +domainAndEndpoint);
responce_headers = xhr.getAllResponseHeaders();
callback(data,textStatus);
},
error: function(xhr, textStatus, errorThrown) {
putMessage(`[${xhr.status}] ${xhr.responseJSON['error']}`);
if ( xhr.status === 401 ) {
location.href = "/logout"
}
}
});
},
post: function (endpoint) {
var postData, callback;
if (typeof arguments[1] === "function") {
postData = {};
callback = arguments[1];
} else {
postData = arguments[1];
callback = arguments[2];
}
$.ajax({
url: apiBase + endpoint,
type: "POST",
data: postData,
headers: {"Authorization": "Bearer " + config.api_user_token},
success: function(data, textStatus) {
console.log("Successful POST API request to " +apiBase+endpoint);
callback(data,textStatus)
},
error: function(xhr, textStatus, errorThrown) {
putMessage(`[${xhr.status}] ${xhr.responseJSON['error']}`);
if ( xhr.status === 401 ) {
location.href = "/logout"
}
}
});
},
postMedia: function (endpoint) {
var postData, callback;
if (typeof arguments[1] === "function") {
postData = {};
callback = arguments[1];
} else {
postData = arguments[1];
callback = arguments[2];
}
$.ajax({
url: apiBase + endpoint,
type: "POST",
data: postData,
contentType: false,
processData: false,
headers: {"Authorization": "Bearer " + config.api_user_token},
success: function(data, textStatus) {
console.log("Successful POST API request to " +apiBase+endpoint);
callback(data,textStatus)
},
error: function(xhr, textStatus, errorThrown) {
putMessage(`[${xhr.status}] ${xhr.responseJSON['error']}`);
if ( xhr.status === 401 ) {
location.href = "/logout"
}
}
});
},
delete: function (endpoint, callback) {
$.ajax({
url: apiBase + endpoint,
type: "DELETE",
headers: {"Authorization": "Bearer " + config.api_user_token},
success: function(data, textStatus) {
console.log("Successful DELETE API request to " +apiBase+endpoint);
callback(data,textStatus)
},
error: function(xhr, textStatus, errorThrown) {
putMessage(`[${xhr.status}] ${xhr.responseJSON['error']}`);
if ( xhr.status === 401 ) {
location.href = "/logout"
}
}
});
},
stream: function (streamType, onData) {
var es = new WebSocket("wss://" + apiBase.substr(8)
+"streaming?access_token=" + config.api_user_token + "&stream=" + streamType);
var listener = function (event) {
console.log("Got Data from Stream " + streamType);
event = JSON.parse(event.data);
event.payload = JSON.parse(event.payload);
onData(event);
};
es.onmessage = listener;
}
};
};

3473
assets/js/replace_emoji.js Normal file

File diff suppressed because it is too large Load Diff

186
assets/js/shortcut.js Normal file
View File

@ -0,0 +1,186 @@
/**
* http://www.openjs.com/scripts/events/keyboard_shortcuts/
* Version : 2.01.B
* By Binny V A
* License : BSD
*/
shortcut = {
'all_shortcuts':{},
'add': function(shortcut_combination,callback,opt) {
var default_options = {
'type':'keydown',
'propagate':false,
'disable_in_input':false,
'target':document,
'keycode':false
}
if(!opt) opt = default_options;
else {
for(var dfo in default_options) {
if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
}
}
var ele = opt.target;
if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
var ths = this;
shortcut_combination = shortcut_combination.toLowerCase();
var func = function(e) {
e = e || window.event;
if(opt['disable_in_input']) {
var element;
if(e.target) element=e.target;
else if(e.srcElement) element=e.srcElement;
if(element.nodeType==3) element=element.parentNode;
if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
}
if (e.keyCode) code = e.keyCode;
else if (e.which) code = e.which;
var character = String.fromCharCode(code).toLowerCase();
if(code == 188) character=",";
if(code == 190) character=".";
var keys = shortcut_combination.split("+");
var kp = 0;
var shift_nums = {
"`":"~",
"1":"!",
"2":"@",
"3":"#",
"4":"$",
"5":"%",
"6":"^",
"7":"&",
"8":"*",
"9":"(",
"0":")",
"-":"_",
"=":"+",
";":":",
"'":"\"",
",":"<",
".":">",
"/":"?",
"\\":"|"
}
var special_keys = {
'esc':27,
'escape':27,
'tab':9,
'space':32,
'return':13,
'enter':13,
'backspace':8,
'scrolllock':145,
'scroll_lock':145,
'scroll':145,
'capslock':20,
'caps_lock':20,
'caps':20,
'numlock':144,
'num_lock':144,
'num':144,
'pause':19,
'break':19,
'insert':45,
'home':36,
'delete':46,
'end':35,
'pageup':33,
'page_up':33,
'pu':33,
'pagedown':34,
'page_down':34,
'pd':34,
'left':37,
'up':38,
'right':39,
'down':40,
'f1':112,
'f2':113,
'f3':114,
'f4':115,
'f5':116,
'f6':117,
'f7':118,
'f8':119,
'f9':120,
'f10':121,
'f11':122,
'f12':123
}
var modifiers = {
shift: { wanted:false, pressed:false},
ctrl : { wanted:false, pressed:false},
alt : { wanted:false, pressed:false},
meta : { wanted:false, pressed:false}
};
if(e.ctrlKey)modifiers.ctrl.pressed = true;
if(e.shiftKey)modifiers.shift.pressed = true;
if(e.altKey)modifiers.alt.pressed = true;
if(e.metaKey) modifiers.meta.pressed = true;
for(var i=0; k=keys[i],i<keys.length; i++) {
//Modifiers
if(k == 'ctrl' || k == 'control') {
kp++;
modifiers.ctrl.wanted = true;
} else if(k == 'shift') {
kp++;
modifiers.shift.wanted = true;
} else if(k == 'alt') {
kp++;
modifiers.alt.wanted = true;
} else if(k == 'meta') {
kp++;
modifiers.meta.wanted = true;
} else if(k.length > 1) {
if(special_keys[k] == code) kp++;
} else if(opt['keycode']) {
if(opt['keycode'] == code) kp++;
} else {
if(character == k) kp++;
else {
if(shift_nums[character] && e.shiftKey) {
character = shift_nums[character];
if(character == k) kp++;
}
}
}
}
if(kp == keys.length &&
modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
modifiers.shift.pressed == modifiers.shift.wanted &&
modifiers.alt.pressed == modifiers.alt.wanted &&
modifiers.meta.pressed == modifiers.meta.wanted) {
callback(e);
if(!opt['propagate']) {
e.cancelBubble = true;
e.returnValue = false;
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
return false;
}
}
}
this.all_shortcuts[shortcut_combination] = {
'callback':func,
'target':ele,
'event': opt['type']
};
if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
else ele['on'+opt['type']] = func;
},
'remove':function(shortcut_combination) {
shortcut_combination = shortcut_combination.toLowerCase();
var binding = this.all_shortcuts[shortcut_combination];
delete(this.all_shortcuts[shortcut_combination])
if(!binding) return;
var type = binding['event'];
var ele = binding['target'];
var callback = binding['callback'];
if(ele.detachEvent) ele.detachEvent('on'+type, callback);
else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
else ele['on'+type] = false;
}
}

1
authorize/.htaccess Normal file
View File

@ -0,0 +1 @@
deny from all

View File

@ -1,970 +0,0 @@
<?php
// defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Class Mastodon_api
*
* PHP version 7.1
*
* Mastodon https://mastodon.social/
* API LIST https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md
*
* @author KwangSeon Yun <middleyks@hanmail.net>
* @copyright KwangSeon Yun
* @license https://raw.githubusercontent.com/yks118/Mastodon-api-php/master/LICENSE MIT License
* @link https://github.com/yks118/Mastodon-api-php
*/
class Mastodon_api {
private $mastodon_url = '';
private $client_id = '';
private $client_secret = '';
private $token = array();
private $scopes = array();
public function __construct () {}
public function __destruct () {}
/**
* _post
*
* curl post
*
* @param string $url
* @param array $data
*
* @return array $response
*/
private function _post ($url,$data = array()) {
$parameters = array();
$parameters[CURLOPT_POST] = 1;
// set access_token
if (isset($this->token['access_token'])) {
$data['access_token'] = $this->token['access_token'];
}
if (count($data)) {
$parameters[CURLOPT_POSTFIELDS] = http_build_query($data);
}
$url = $this->mastodon_url.$url;
$response = $this->get_content_curl($url,$parameters);
return $response;
}
/**
* _get
*
* @param string $url
* @param array $data
*
* @return array $response
*/
private function _get ($url,$data = array()) {
$parameters = array();
// set authorization bearer
if (isset($this->token['access_token'])) {
$authorization = 'Authorization: '.$this->token['token_type'].' '.$this->token['access_token'];
$parameters[CURLOPT_HTTPHEADER] = array('Content-Type: application/json',$authorization);
}
$url = $this->mastodon_url.$url;
if (count($data)) {
$url .= '?'.http_build_query($data);
}
$response = $this->get_content_curl($url,$parameters);
return $response;
}
/**
* _patch
*
* @param string $url
* @param array $data
*
* @return array $parameters
*/
private function _patch ($url,$data = array()) {
$parameters = array();
$parameters[CURLOPT_CUSTOMREQUEST] = 'PATCH';
// set authorization bearer
if (isset($this->token['access_token'])) {
$authorization = 'Authorization: '.$this->token['token_type'].' '.$this->token['access_token'];
$parameters[CURLOPT_HTTPHEADER] = array('Content-Type: application/json',$authorization);
}
if (count($data)) {
$parameters[CURLOPT_POSTFIELDS] = json_encode($data);
}
$url = $this->mastodon_url.$url;
$response = $this->get_content_curl($url,$parameters);
return $response;
}
/**
* _delete
*
* @param string $url
*
* @return array $response
*/
private function _delete ($url) {
$parameters = array();
$parameters[CURLOPT_CUSTOMREQUEST] = 'DELETE';
// set authorization bearer
if (isset($this->token['access_token'])) {
$authorization = 'Authorization: '.$this->token['token_type'].' '.$this->token['access_token'];
$parameters[CURLOPT_HTTPHEADER] = array('Content-Type: application/json',$authorization);
}
$url = $this->mastodon_url.$url;
$response = $this->get_content_curl($url,$parameters);
return $response;
}
/**
* get_content_curl
*
* @param string $url
* @param array $parameters
*
* @return array $data
*/
protected function get_content_curl ($url,$parameters = array()) {
$data = array();
// set CURLOPT_USERAGENT
if (!isset($parameters[CURLOPT_USERAGENT])) {
if (isset($_SERVER['HTTP_USER_AGENT'])) {
$parameters[CURLOPT_USERAGENT] = $_SERVER['HTTP_USER_AGENT'];
} else {
// default IE11
$parameters[CURLOPT_USERAGENT] = 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko';
}
}
// check curl_init
if (function_exists('curl_init')) {
$ch = curl_init();
// url 설정
curl_setopt($ch,CURLOPT_URL,$url);
foreach ($parameters as $key => $value) {
curl_setopt($ch,$key,$value);
}
// https
if (!isset($parameters[CURLOPT_SSL_VERIFYPEER])) {
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
}
if (!isset($parameters[CURLOPT_SSLVERSION])) {
curl_setopt($ch,CURLOPT_SSLVERSION,6);
}
// no header
if (!isset($parameters[CURLOPT_HEADER])) {
curl_setopt($ch,CURLOPT_HEADER,0);
}
// POST / GET (default : GET)
if (!isset($parameters[CURLOPT_POST]) && !isset($parameters[CURLOPT_CUSTOMREQUEST])) {
curl_setopt($ch,CURLOPT_POST,0);
}
// response get php value
if (!isset($parameters[CURLOPT_RETURNTRANSFER])) {
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
}
// HTTP2
if (!isset($parameters[CURLOPT_HTTP_VERSION])) {
curl_setopt($ch,CURLOPT_HTTP_VERSION,3);
}
if (!isset($parameters[CURLINFO_HEADER_OUT])) {
curl_setopt($ch,CURLINFO_HEADER_OUT,TRUE);
}
$data['html'] = json_decode(curl_exec($ch),true);
$data['response'] = curl_getinfo($ch);
curl_close($ch);
}
return $data;
}
/**
* set_url
*
* @param string $path
*/
public function set_url ($path) {
$this->mastodon_url = $path;
}
/**
* set_client
*
* @param string $id
* @param string $secret
*/
public function set_client ($id,$secret) {
$this->client_id = $id;
$this->client_secret = $secret;
}
/**
* set_token
*
* @param string $token
* @param string $type
*/
public function set_token ($token,$type) {
$this->token['access_token'] = $token;
$this->token['token_type'] = $type;
}
/**
* set_scopes
*
* @param array $scopes read / write / follow
*/
public function set_scopes ($scopes) {
$this->scopes = $scopes;
}
/**
* create_app
*
* @param string $client_name
* @param array $scopes read / write / follow
* @param string $redirect_uris
* @param string $website
*
* @return array $response
* int $response['id']
* string $response['redirect_uri']
* string $response['client_id']
* string $response['client_secret']
*/
public function create_app ($client_name,$scopes = array(),$redirect_uris = '',$website = '') {
$parameters = array();
if (count($scopes) == 0) {
if (count($this->scopes) == 0) {
$scopes = array('read','write','follow');
} else {
$scopes = $this->scopes;
}
}
$parameters['client_name'] = $client_name;
$parameters['scopes'] = implode(' ',$scopes);
if (empty($redirect_uris)) {
$parameters['redirect_uris'] = 'urn:ietf:wg:oauth:2.0:oob';
} else {
$parameters['redirect_uris'] = $redirect_uris;
}
if ($website) {
$parameters['website'] = $website;
}
$response = $this->_post('/api/v1/apps',$parameters);
if (isset($response['html']['client_id'])) {
$this->client_id = $response['html']['client_id'];
$this->client_secret = $response['html']['client_secret'];
}
return $response;
}
/**
* login
*
* @param string $id E-mail Address
* @param string $password Password
*
* @return array $response
* string $response['access_token']
* string $response['token_type'] bearer
* string $response['scope'] read
* int $response['created_at'] time
*/
public function login ($id,$password) {
$parameters = array();
$parameters['client_id'] = $this->client_id;
$parameters['client_secret'] = $this->client_secret;
$parameters['grant_type'] = 'password';
$parameters['username'] = $id;
$parameters['password'] = $password;
if (count($this->scopes) == 0) {
$parameters['scope'] = implode(' ',array('read','write','follow'));
} else {
$parameters['scope'] = implode(' ',$this->scopes);
}
$response = $this->_post('/oauth/token',$parameters);
if (isset($response['html']["access_token"])) {
$this->token['access_token'] = $response['html']['access_token'];
$this->token['token_type'] = $response['html']['token_type'];
}
return $response;
}
public function get_access_token ($redirect_uri,$code) {
$parameters = array();
$parameters['grant_type'] = 'authorization_code';
$parameters['redirect_uri'] = $redirect_uri;
$parameters['client_id'] = $this->client_id;
$parameters['client_secret'] = $this->client_secret;
$parameters['code'] = $code;
$response = $this->_post('/oauth/token',$parameters);
if (isset($response['html']["access_token"])) {
$this->token['access_token'] = $response['html']['access_token'];
$this->token['token_type'] = $response['html']['token_type'];
}
return $response;
}
/**
* accounts
*
* @see https://your-domain/web/accounts/:id
*
* @param int $id
*
* @return array $response
* int $response['id']
* string $response['username']
* string $response['acct']
* string $response['display_name'] The name to display in the user's profile
* bool $response['locked']
* string $response['created_at']
* int $response['followers_count']
* int $response['following_count']
* int $response['statuses_count']
* string $response['note'] A new biography for the user
* string $response['url']
* string $response['avatar'] A base64 encoded image to display as the user's avatar
* string $response['avatar_static']
* string $response['header'] A base64 encoded image to display as the user's header image
* string $response['header_static']
*/
public function accounts ($id) {
$response = $this->_get('/api/v1/accounts/'.$id);
return $response;
}
/**
* accounts_verify_credentials
*
* Getting the current user
*
* @return array $response
*/
public function accounts_verify_credentials () {
$response = $this->_get('/api/v1/accounts/verify_credentials');
return $response;
}
/**
* accounts_update_credentials
*
* Updating the current user
*
* @param array $parameters
* string $parameters['display_name'] The name to display in the user's profile
* string $parameters['note'] A new biography for the user
* string $parameters['avatar'] A base64 encoded image to display as the user's avatar
* string $parameters['header'] A base64 encoded image to display as the user's header image
*
* @return array $response
*/
public function accounts_update_credentials ($parameters) {
$response = $this->_patch('/api/v1/accounts/update_credentials',$parameters);
return $response;
}
/**
* accounts_followers
*
* @see https://your-domain/web/accounts/:id
*
* @param int $id
*
* @return array $response
*/
public function accounts_followers ($id) {
$response = $this->_get('/api/v1/accounts/'.$id.'/followers');
return $response;
}
/**
* accounts_following
*
* @see https://your-domain/web/accounts/:id
*
* @param int $id
*
* @return array $response
*/
public function accounts_following ($id) {
$response = $this->_get('/api/v1/accounts/'.$id.'/following');
return $response;
}
/**
* accounts_statuses
*
* @see https://your-domain/web/accounts/:id
*
* @param int $id
*
* @return array $response
*/
public function accounts_statuses ($id) {
$response = $this->_get('/api/v1/accounts/'.$id.'/statuses');
return $response;
}
/**
* accounts_follow
*
* @see https://your-domain/web/accounts/:id
*
* @param int $id
*
* @return array $response
*/
public function accounts_follow ($id) {
$response = $this->_post('/api/v1/accounts/'.$id.'/follow');
return $response;
}
/**
* accounts_unfollow
*
* @see https://your-domain/web/accounts/:id
*
* @param int $id
*
* @return array $response
*/
public function accounts_unfollow ($id) {
$response = $this->_post('/api/v1/accounts/'.$id.'/unfollow');
return $response;
}
/**
* accounts_block
*
* @see https://your-domain/web/accounts/:id
*
* @param int $id
*
* @return array $response
*/
public function accounts_block ($id) {
$response = $this->_post('/api/v1/accounts/'.$id.'/block');
return $response;
}
/**
* accounts_unblock
*
* @see https://your-domain/web/accounts/:id
*
* @param int $id
*
* @return array $response
*/
public function accounts_unblock ($id) {
$response = $this->_post('/api/v1/accounts/'.$id.'/unblock');
return $response;
}
/**
* accounts_mute
*
* @see https://your-domain/web/accounts/:id
*
* @param int $id
*
* @return array $response
*/
public function accounts_mute ($id) {
$response = $this->_post('/api/v1/accounts/'.$id.'/mute');
return $response;
}
/**
* accounts_unmute
*
* @see https://your-domain/web/accounts/:id
*
* @param int $id
*
* @return array $response
*/
public function accounts_unmute ($id) {
$response = $this->_post('/api/v1/accounts/'.$id.'/unmute');
return $response;
}
/**
* accounts_relationships
*
* @see https://your-domain/web/accounts/:id
*
* @param array $parameters
* int $parameters['id']
*
* @return array $response
* int $response['id']
* bool $response['following']
* bool $response['followed_by']
* bool $response['blocking']
* bool $response['muting']
* bool $response['requested']
*/
public function accounts_relationships ($parameters) {
$response = $this->_get('/api/v1/accounts/relationships',$parameters);
return $response;
}
/**
* accounts_search
*
* @param array $parameters
* string $parameters['q']
* int $parameters['limit'] default : 40
*
* @return array $response
*/
public function accounts_search ($parameters) {
$response = $this->_get('/api/v1/accounts/search',$parameters);
return $response;
}
/**
* blocks
*
* @return array $response
*/
public function blocks () {
$response = $this->_get('/api/v1/blocks');
return $response;
}
/**
* favourites
*
* @return array $response
*/
public function favourites () {
$response = $this->_get('/api/v1/favourites');
return $response;
}
/**
* follow_requests
*
* @return array $response
*/
public function follow_requests () {
$response = $this->_get('/api/v1/follow_requests');
return $response;
}
/**
* follow_requests_authorize
*
* @see https://your-domain/web/accounts/:id
*
* @param int $id
*
* @return array $response
*/
public function follow_requests_authorize ($id) {
$response = $this->_post('/api/v1/follow_requests/authorize',array('id'=>$id));
return $response;
}
/**
* follow_requests_reject
*
* @see https://your-domain/web/accounts/:id
*
* @param int $id
* @return array $response
*/
public function follow_requests_reject ($id) {
$response = $this->_post('/api/v1/follow_requests/reject',array('id'=>$id));
return $response;
}
/**
* follows
*
* Following a remote user
*
* @param string $uri username@domain of the person you want to follow
* @return array $response
*/
public function follows ($uri) {
$response = $this->_post('/api/v1/follows',array('uri'=>$uri));
return $response;
}
/**
* instance
*
* Getting instance information
*
* @return array $response
* string $response['uri']
* string $response['title']
* string $response['description']
* string $response['email']
*/
public function instance () {
$response = $this->_get('/api/v1/instance');
return $response;
}
/**
* media
*
* Uploading a media attachment
*
* @param string $file_path local path / http path
*
* @return array $response
* int $response['id'] ID of the attachment
* string $response['type'] One of: "image", "video", "gifv"
* string $response['url'] URL of the locally hosted version of the image
* string $response['remote_url'] For remote images, the remote URL of the original image
* string $response['preview_url'] URL of the preview image
* string $response['text_url'] Shorter URL for the image, for insertion into text (only present on local images)
*/
public function media ($file_path) {
$url = $this->mastodon_url.'/api/v1/media';
$parameters = $data = array();
$parameters[CURLOPT_HTTPHEADER] = array('Content-Type'=>'multipart/form-data');
$parameters[CURLOPT_POST] = true;
// set access_token
if (isset($this->token['access_token'])) {
$parameters[CURLOPT_POSTFIELDS]['access_token'] = $this->token['access_token'];
}
if (is_file($file_path)) {
$mime_type = mime_content_type($file_path);
$cf = curl_file_create($file_path,$mime_type,'file');
$parameters[CURLOPT_POSTFIELDS]['file'] = $cf;
}
$response = $this->get_content_curl($url,$parameters);
return $response;
}
/**
* mutes
*
* Fetching a user's mutes
*
* @return array $response
*/
public function mutes () {
$response = $this->_get('/api/v1/mutes');
return $response;
}
/**
* notifications
*
* @param int $id
*
* @return array $response
*/
public function notifications ($id = 0) {
$url = '/api/v1/notifications';
if ($id > 0) {
$url .= '/'.$id;
}
$response = $this->_get($url);
return $response;
}
/**
* notifications_clear
*
* Clearing notifications
*
* @return array $response
*/
public function notifications_clear () {
$response = $this->_post('/api/v1/notifications/clear');
return $response;
}
/**
* get_reports
*
* Fetching a user's reports
*
* @return array $response
*/
public function get_reports () {
$response = $this->_get('/api/v1/reports');
return $response;
}
/**
* post_reports
*
* Reporting a user
*
* @param array $parameters
* int $parameters['account_id'] The ID of the account to report
* int $parameters['status_ids'] The IDs of statuses to report (can be an array)
* string $parameters['comment'] A comment to associate with the report.
*
* @return array $response
*/
public function post_reports ($parameters) {
$response = $this->_post('/api/v1/reports',$parameters);
return $response;
}
/**
* search
*
* Searching for content
*
* @param array $parameters
* string $parameters['q'] The search query
* string $parameters['resolve'] Whether to resolve non-local accounts
*
* @return array $response
*/
public function search ($parameters) {
$response = $this->_get('/api/v1/search',$parameters);
return $response;
}
/**
* statuses
*
* Fetching a status
*
* @param int $id
*
* @return array $response
*/
public function statuses ($id) {
$response = $this->_get('/api/v1/statuses/'.$id);
return $response;
}
/**
* statuses_context
*
* Getting status context
*
* @param int $id
*
* @return array $response
*/
public function statuses_context ($id) {
$response = $this->_get('/api/v1/statuses/'.$id.'/context');
return $response;
}
/**
* statuses_card
*
* Getting a card associated with a status
*
* @param int $id
*
* @return array $response
*/
public function statuses_card ($id) {
$response = $this->_get('/api/v1/statuses/'.$id.'/card');
return $response;
}
/**
* statuses_reblogged_by
*
* Getting who reblogged a status
*
* @param int $id
*
* @return array $response
*/
public function statuses_reblogged_by ($id) {
$response = $this->_get('/api/v1/statuses/'.$id.'/reblogged_by');
return $response;
}
/**
* statuses_favourited_by
*
* Getting who favourited a status
*
* @param int $id
*
* @return array $response
*/
public function statuses_favourited_by ($id) {
$response = $this->_get('/api/v1/statuses/'.$id.'/favourited_by');
return $response;
}
/**
* post_statuses
*
* @param array $parameters
* string $parameters['status'] The text of the status
* int $parameters['in_reply_to_id'] (optional): local ID of the status you want to reply to
* int $parameters['media_ids'] (optional): array of media IDs to attach to the status (maximum 4)
* string $parameters['sensitive'] (optional): set this to mark the media of the status as NSFW
* string $parameters['spoiler_text'] (optional): text to be shown as a warning before the actual content
* string $parameters['visibility'] (optional): either "direct", "private", "unlisted" or "public"
*
* @return array $response
*/
public function post_statuses ($parameters) {
$response = $this->_post('/api/v1/statuses',$parameters);
return $response;
}
/**
* delete_statuses
*
* Deleting a status
*
* @param int $id
*
* @return array $response empty
*/
public function delete_statuses ($id) {
$response = $this->_delete('/api/v1/statuses/'.$id);
return $response;
}
/**
* statuses_reblog
*
* Reblogging a status
*
* @param int $id
*
* @return array $response
*/
public function statuses_reblog ($id) {
$response = $this->_post('/api/v1/statuses/'.$id.'/reblog');
return $response;
}
/**
* statuses_unreblog
*
* Unreblogging a status
*
* @param int $id
*
* @return array $response
*/
public function statuses_unreblog ($id) {
$response = $this->_post('/api/v1/statuses/'.$id.'/unreblog');
return $response;
}
/**
* statuses_favourite
*
* Favouriting a status
*
* @param int $id
*
* @return array $response
*/
public function statuses_favourite ($id) {
$response = $this->_post('/api/v1/statuses/'.$id.'/favourite');
return $response;
}
/**
* statuses_unfavourite
*
* Unfavouriting a status
*
* @param int $id
*
* @return array $response
*/
public function statuses_unfavourite ($id) {
$response = $this->_post('/api/v1/statuses/'.$id.'/unfavourite');
return $response;
}
/**
* timelines_home
*
* @return array $response
*/
public function timelines_home () {
$response = $this->_get('/api/v1/timelines/home');
return $response;
}
/**
* timelines_public
*
* @param array $parameters
* bool $parameters['local'] Only return statuses originating from this instance
*
* @return array $response
*/
public function timelines_public ($parameters = array()) {
$response = $this->_get('/api/v1/timelines/public',$parameters);
return $response;
}
/**
* timelines_tag
*
* @param string $hashtag
* @param array $parameters
* bool $parameters['local'] Only return statuses originating from this instance
*
* @return array $response
*/
public function timelines_tag ($hashtag,$parameters = array()) {
$response = $this->_get('/api/v1/timelines/tag/'.$hashtag,$parameters);
return $response;
}
}

View File

@ -1,19 +0,0 @@
# Mastodon-api-php
A GNU Social-compatible microblogging server https://mastodon.social PHP API
## How to use
require_once '/path/Mastodon_api.php';<br />
<br />
$mastodon_api = new Mastodon_api();<br />
$mastodon_api->set_url('Mastodon url');<br />
<br />
// print_r($mastodon_api->create_app('APP Name',null,null,'Mastodon url'));<br />
$mastodon_api->set_client('client_id','client_secret');<br />
<br />
// print_r($mastodon_api->login('your login email','your login password'));<br />
$mastodon_api->set_token('access_token','token_type');<br />
<br />
$mastodon_api->timelines_home();
## Test Mastodon
https://ery.kr

View File

@ -1,82 +0,0 @@
<?php
#!/usr/bin/env php
namespace HalcyonSuite\HalcyonForMastodon;
require_once('database.php');
require_once('Mastodon-api-php/Mastodon_api.php');
use HalcyonSuite\HalcyonForMastodon\Database;
use PDO;
use Exception;
/*-------------------
class for halcyon
--------------------*/
class Mastodon extends \Mastodon_api
{
function __construct(){
$appSettings = parse_ini_file('../../config.ini', true);
$this->clientName = $appSettings["App"]["api_client_name"];
$this->clientRedirectUris = $appSettings["App"]["api_client_website"].'/auth urn:ietf:wg:oauth:2.0:oob';
$this->clientWebsite = $appSettings["App"]["api_client_website"];
$this->clientScopes = array('read', 'write', 'follow');
$this->instances = array();
$this->dbHost = $appSettings["Mysql"]["db_host"];
$this->dbUser = $appSettings["Mysql"]["db_user"];
$this->dbPass = $appSettings["Mysql"]["db_pass"];
$this->dbName = $appSettings["Mysql"]["db_name"];
$this->database = new Database($this->dbHost, $this->dbUser, $this->dbPass, $this->dbName);
$this->readInstances();
}
/* note: $domainって書いてあるけど、ドメインじゃなくてURLです。すみません */
private function newInstance($domain)
{
$res = $this->create_app($this->clientName, $this->clientScopes, $this->clientRedirectUris, $this->clientWebsite);
if (isset($res['html']['client_id'])) {
$this->instances[$domain] = $res['html'];
$this->database->dbExecute("insert into instances(domain, client_id, client_secret) values(?,?,?)", array($domain, $res['html']['client_id'], $res['html']['client_secret']));
// insert into instances(domain, client_id, client_secret) values($domain, $client_id, $client_secret)
}else{
throw new Exception("Invalid instance");
}
}
public function selectInstance($domain)
{
$this->set_url($domain);
if (!$this->instanceExists($domain)) {
$this->newInstance($domain);
}
$this->set_client($this->instances[$domain]['client_id'], $this->instances[$domain]['client_secret']);
}
public function getInstance($domain)
{
$this->set_url($domain);
if (!$this->instanceExists($domain)) {
$this->newInstance($domain);
}
return array('client_id' => $this->instances[$domain]['client_id'], 'client_secret' => $this->instances[$domain]['client_secret']);
}
public function instanceExists($domain)
{
return isset($this->instances[$domain]);
}
private function readInstances()
{
$stmt = $this->database->dbExecute("select domain,client_id,client_secret from instances");
foreach($stmt->fetchAll(PDO::FETCH_ASSOC) as $row){
$this->instances[$row['domain']] = $row;
}
}
}
?>

View File

@ -1,50 +0,0 @@
<?php
#!/usr/bin/env php
namespace HalcyonSuite\HalcyonForMastodon;
use PDO;
use Exception;
class Database{
public function __construct($dbhost, $dbuser, $dbpass, $dbname){
$this->dbhost = $dbhost;
$this->dbuser = $dbuser;
$this->dbpass = $dbpass;
$this->dbname = $dbname;
$this->dsn = "mysql:dbname=".$this->dbname.";host=".$this->dbhost.";charset=utf8";
$this->connecting = false;
$this->dbConnect();
}
public function dbConnect($commit=True){
try{
$dbh = new PDO($this->dsn, $this->dbuser, $this->dbpass);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
if(!$commit){
$dbh->beginTransaction();
}
}catch (PDOException $e){
throw new Exception($e);
}
$this->dbh = $dbh;
$this->connecting = true;
return $dbh;
}
public function dbClose(){
$this->dbh = Null;
$this->connecting = false;
}
public function dbExecute($sql, $attr = null){
if ($attr === null) {
$attr = array();
}
if (!$this->connecting) {
$this->dbConnect();
}
$stmt = $this->dbh->prepare($sql);
$stmt->execute($attr);
return $stmt;
}
}
?>

View File

View File

@ -0,0 +1,374 @@
<?php
/**
* Class Mastodon_api
*
* PHP version 7.1
*
* Mastodon https://mastodon.social/
* API LIST https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md
*
* @author KwangSeon Yun <middleyks@hanmail.net>
* @copyright KwangSeon Yun
* @license https://raw.githubusercontent.com/yks118/Mastodon-api-php/master/LICENSE MIT License
* @link https://github.com/yks118/Mastodon-api-php
*/
class Mastodon_api {
private $mastodon_url = '';
private $client_id = '';
private $client_secret = '';
private $token = array();
private $scopes = array();
public function __construct () {}
public function __destruct () {}
private function _post ($url,$data = array()) {
$parameters = array();
$parameters[CURLOPT_POST] = 1;
if (isset($this->token['access_token'])) {
$data['access_token'] = $this->token['access_token'];
}
if (count($data)) {
$parameters[CURLOPT_POSTFIELDS] = http_build_query($data);
}
$url = $this->mastodon_url.$url;
$response = $this->get_content_curl($url,$parameters);
return $response;
}
private function _get ($url,$data = array()) {
$parameters = array();
if (isset($this->token['access_token'])) {
$authorization = 'Authorization: '.$this->token['token_type'].' '.$this->token['access_token'];
$parameters[CURLOPT_HTTPHEADER] = array('Content-Type: application/json',$authorization);
}
$url = $this->mastodon_url.$url;
if (count($data)) {
$url .= '?'.http_build_query($data);
}
$response = $this->get_content_curl($url,$parameters);
return $response;
}
private function _patch ($url,$data = array()) {
$parameters = array();
$parameters[CURLOPT_CUSTOMREQUEST] = 'PATCH';
if (isset($this->token['access_token'])) {
$authorization = 'Authorization: '.$this->token['token_type'].' '.$this->token['access_token'];
$parameters[CURLOPT_HTTPHEADER] = array('Content-Type: application/json',$authorization);
}
if (count($data)) {
$parameters[CURLOPT_POSTFIELDS] = json_encode($data);
}
$url = $this->mastodon_url.$url;
$response = $this->get_content_curl($url,$parameters);
return $response;
}
private function _delete ($url) {
$parameters = array();
$parameters[CURLOPT_CUSTOMREQUEST] = 'DELETE';
if (isset($this->token['access_token'])) {
$authorization = 'Authorization: '.$this->token['token_type'].' '.$this->token['access_token'];
$parameters[CURLOPT_HTTPHEADER] = array('Content-Type: application/json',$authorization);
}
$url = $this->mastodon_url.$url;
$response = $this->get_content_curl($url,$parameters);
return $response;
}
protected function get_content_curl ($url,$parameters = array()) {
$data = array();
if (!isset($parameters[CURLOPT_USERAGENT])) {
if (isset($_SERVER['HTTP_USER_AGENT'])) {
$parameters[CURLOPT_USERAGENT] = $_SERVER['HTTP_USER_AGENT'];
} else {
$parameters[CURLOPT_USERAGENT] = 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko';
}
}
if (function_exists('curl_init')) {
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
foreach ($parameters as $key => $value) {
curl_setopt($ch,$key,$value);
}
if (!isset($parameters[CURLOPT_SSL_VERIFYPEER])) {
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
}
if (!isset($parameters[CURLOPT_SSLVERSION])) {
curl_setopt($ch,CURLOPT_SSLVERSION,6);
}
if (!isset($parameters[CURLOPT_HEADER])) {
curl_setopt($ch,CURLOPT_HEADER,0);
}
if (!isset($parameters[CURLOPT_POST]) && !isset($parameters[CURLOPT_CUSTOMREQUEST])) {
curl_setopt($ch,CURLOPT_POST,0);
}
if (!isset($parameters[CURLOPT_RETURNTRANSFER])) {
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
}
if (!isset($parameters[CURLOPT_HTTP_VERSION])) {
curl_setopt($ch,CURLOPT_HTTP_VERSION,3);
}
if (!isset($parameters[CURLINFO_HEADER_OUT])) {
curl_setopt($ch,CURLINFO_HEADER_OUT,TRUE);
}
$data['html'] = json_decode(curl_exec($ch),true);
$data['response'] = curl_getinfo($ch);
curl_close($ch);
}
return $data;
}
public function set_url ($path) {
$this->mastodon_url = $path;
}
public function set_client ($id,$secret) {
$this->client_id = $id;
$this->client_secret = $secret;
}
public function set_token ($token,$type) {
$this->token['access_token'] = $token;
$this->token['token_type'] = $type;
}
public function set_scopes ($scopes) {
$this->scopes = $scopes;
}
public function create_app ($client_name,$scopes = array(),$redirect_uris = '',$website = '') {
$parameters = array();
if (count($scopes) == 0) {
if (count($this->scopes) == 0) {
$scopes = array('read','write','follow');
} else {
$scopes = $this->scopes;
}
}
$parameters['client_name'] = $client_name;
$parameters['scopes'] = implode(' ',$scopes);
if (empty($redirect_uris)) {
$parameters['redirect_uris'] = 'urn:ietf:wg:oauth:2.0:oob';
} else {
$parameters['redirect_uris'] = $redirect_uris;
}
if ($website) {
$parameters['website'] = $website;
}
$response = $this->_post('/api/v1/apps',$parameters);
if (isset($response['html']['client_id'])) {
$this->client_id = $response['html']['client_id'];
$this->client_secret = $response['html']['client_secret'];
}
return $response;
}
public function login ($id,$password) {
$parameters = array();
$parameters['client_id'] = $this->client_id;
$parameters['client_secret'] = $this->client_secret;
$parameters['grant_type'] = 'password';
$parameters['username'] = $id;
$parameters['password'] = $password;
if (count($this->scopes) == 0) {
$parameters['scope'] = implode(' ',array('read','write','follow'));
} else {
$parameters['scope'] = implode(' ',$this->scopes);
}
$response = $this->_post('/oauth/token',$parameters);
if (isset($response['html']["access_token"])) {
$this->token['access_token'] = $response['html']['access_token'];
$this->token['token_type'] = $response['html']['token_type'];
}
return $response;
}
public function get_access_token ($redirect_uri,$code) {
$parameters = array();
$parameters['grant_type'] = 'authorization_code';
$parameters['redirect_uri'] = $redirect_uri;
$parameters['client_id'] = $this->client_id;
$parameters['client_secret'] = $this->client_secret;
$parameters['code'] = $code;
$response = $this->_post('/oauth/token',$parameters);
if (isset($response['html']["access_token"])) {
$this->token['access_token'] = $response['html']['access_token'];
$this->token['token_type'] = $response['html']['token_type'];
}
return $response;
}
public function accounts ($id) {
$response = $this->_get('/api/v1/accounts/'.$id);
return $response;
}
public function accounts_verify_credentials () {
$response = $this->_get('/api/v1/accounts/verify_credentials');
return $response;
}
public function accounts_update_credentials ($parameters) {
$response = $this->_patch('/api/v1/accounts/update_credentials',$parameters);
return $response;
}
public function accounts_followers ($id) {
$response = $this->_get('/api/v1/accounts/'.$id.'/followers');
return $response;
}
public function accounts_following ($id) {
$response = $this->_get('/api/v1/accounts/'.$id.'/following');
return $response;
}
public function accounts_statuses ($id) {
$response = $this->_get('/api/v1/accounts/'.$id.'/statuses');
return $response;
}
public function accounts_follow ($id) {
$response = $this->_post('/api/v1/accounts/'.$id.'/follow');
return $response;
}
public function accounts_unfollow ($id) {
$response = $this->_post('/api/v1/accounts/'.$id.'/unfollow');
return $response;
}
public function accounts_block ($id) {
$response = $this->_post('/api/v1/accounts/'.$id.'/block');
return $response;
}
public function accounts_unblock ($id) {
$response = $this->_post('/api/v1/accounts/'.$id.'/unblock');
return $response;
}
public function accounts_mute ($id) {
$response = $this->_post('/api/v1/accounts/'.$id.'/mute');
return $response;
}
public function accounts_unmute ($id) {
$response = $this->_post('/api/v1/accounts/'.$id.'/unmute');
return $response;
}
public function accounts_relationships ($parameters) {
$response = $this->_get('/api/v1/accounts/relationships',$parameters);
return $response;
}
public function accounts_search ($parameters) {
$response = $this->_get('/api/v1/accounts/search',$parameters);
return $response;
}
public function blocks () {
$response = $this->_get('/api/v1/blocks');
return $response;
}
public function favourites () {
$response = $this->_get('/api/v1/favourites');
return $response;
}
public function follow_requests () {
$response = $this->_get('/api/v1/follow_requests');
return $response;
}
public function follow_requests_authorize ($id) {
$response = $this->_post('/api/v1/follow_requests/authorize',array('id'=>$id));
return $response;
}
public function follow_requests_reject ($id) {
$response = $this->_post('/api/v1/follow_requests/reject',array('id'=>$id));
return $response;
}
public function follows ($uri) {
$response = $this->_post('/api/v1/follows',array('uri'=>$uri));
return $response;
}
public function instance () {
$response = $this->_get('/api/v1/instance');
return $response;
}
public function media ($file_path) {
$url = $this->mastodon_url.'/api/v1/media';
$parameters = $data = array();
$parameters[CURLOPT_HTTPHEADER] = array('Content-Type'=>'multipart/form-data');
$parameters[CURLOPT_POST] = true;
if (isset($this->token['access_token'])) {
$parameters[CURLOPT_POSTFIELDS]['access_token'] = $this->token['access_token'];
}
if (is_file($file_path)) {
$mime_type = mime_content_type($file_path);
$cf = curl_file_create($file_path,$mime_type,'file');
$parameters[CURLOPT_POSTFIELDS]['file'] = $cf;
}
$response = $this->get_content_curl($url,$parameters);
return $response;
}
public function mutes () {
$response = $this->_get('/api/v1/mutes');
return $response;
}
public function notifications ($id = 0) {
$url = '/api/v1/notifications';
if ($id > 0) {
$url .= '/'.$id;
}
$response = $this->_get($url);
return $response;
}
public function notifications_clear () {
$response = $this->_post('/api/v1/notifications/clear');
return $response;
}
public function get_reports () {
$response = $this->_get('/api/v1/reports');
return $response;
}
public function post_reports ($parameters) {
$response = $this->_post('/api/v1/reports',$parameters);
return $response;
}
public function search ($parameters) {
$response = $this->_get('/api/v1/search',$parameters);
return $response;
}
public function statuses ($id) {
$response = $this->_get('/api/v1/statuses/'.$id);
return $response;
}
public function statuses_context ($id) {
$response = $this->_get('/api/v1/statuses/'.$id.'/context');
return $response;
}
public function statuses_card ($id) {
$response = $this->_get('/api/v1/statuses/'.$id.'/card');
return $response;
}
public function statuses_reblogged_by ($id) {
$response = $this->_get('/api/v1/statuses/'.$id.'/reblogged_by');
return $response;
}
public function statuses_favourited_by ($id) {
$response = $this->_get('/api/v1/statuses/'.$id.'/favourited_by');
return $response;
}
public function post_statuses ($parameters) {
$response = $this->_post('/api/v1/statuses',$parameters);
return $response;
}
public function delete_statuses ($id) {
$response = $this->_delete('/api/v1/statuses/'.$id);
return $response;
}
public function statuses_reblog ($id) {
$response = $this->_post('/api/v1/statuses/'.$id.'/reblog');
return $response;
}
public function statuses_unreblog ($id) {
$response = $this->_post('/api/v1/statuses/'.$id.'/unreblog');
return $response;
}
public function statuses_favourite ($id) {
$response = $this->_post('/api/v1/statuses/'.$id.'/favourite');
return $response;
}
public function statuses_unfavourite ($id) {
$response = $this->_post('/api/v1/statuses/'.$id.'/unfavourite');
return $response;
}
public function timelines_home () {
$response = $this->_get('/api/v1/timelines/home');
return $response;
}
public function timelines_public ($parameters = array()) {
$response = $this->_get('/api/v1/timelines/public',$parameters);
return $response;
}
public function timelines_tag ($hashtag,$parameters = array()) {
$response = $this->_get('/api/v1/timelines/tag/'.$hashtag,$parameters);
return $response;
}
}
?>

51
authorize/mastodon.php Normal file
View File

@ -0,0 +1,51 @@
<?php
namespace HalcyonSuite\HalcyonForMastodon;
require_once('mastodon-api/mastodon.php');
use Exception;
class Mastodon extends \Mastodon_api {
function __construct(){
$appSettings = parse_ini_file('../config.ini',true);
$this->datadir = "../data";
$this->clientName = $appSettings["App"]["api_client_name"];
$this->clientRedirectUris = $appSettings["App"]["api_client_website"].'/auth urn:ietf:wg:oauth:2.0:oob';
$this->clientWebsite = $appSettings["App"]["api_client_website"];
$this->clientScopes = array('read','write','follow');
$this->instances = array();
$this->readInstances();
}
private function newInstance($domain) {
$res = $this->create_app($this->clientName,$this->clientScopes,$this->clientRedirectUris,$this->clientWebsite);
if(isset($res['html']['client_id'])) {
$this->instances[$domain] = $res['html'];
file_put_contents($this->datadir."/".substr($domain,8).".txt",json_encode(array("client_id" => $res['html']['client_id'],"client_secret" => $res['html']['client_secret'])));
}
else {
throw new Exception("Invalid instance");
}
}
public function selectInstance($domain) {
$this->set_url($domain);
if(!$this->instanceExists($domain)) {
$this->newInstance($domain);
}
$this->set_client($this->instances[$domain]['client_id'],$this->instances[$domain]['client_secret']);
}
public function getInstance($domain) {
$this->set_url($domain);
if (!$this->instanceExists($domain)) {
$this->newInstance($domain);
}
return array('client_id' => $this->instances[$domain]['client_id'],'client_secret' => $this->instances[$domain]['client_secret']);
}
public function instanceExists($domain) {
return isset($this->instances[$domain]);
}
private function readInstances() {
$instlist = array_diff(scandir($this->datadir),array("..",".",".htaccess"));
foreach($instlist as $index => $item) {
$itemname = "https://".substr($item,0,-4);
$this->instances[$itemname] = json_decode(file_get_contents($this->datadir."/".$item),true);
}
}
}
?>

View File

@ -2,10 +2,3 @@
[App]
api_client_name = APPLICATION'S NAME
api_client_website = HTTPS://YOURDOMAIN.COM/
; MySQL Settings
[Mysql]
db_host = YOUR DATABASE'S HOST
db_user = YOUR DATABASE'S USER
db_pass = YOUR DATABASE'S PASSWORD
db_name = YOUR DATABASE'S NAME

1
data/.htaccess Normal file
View File

@ -0,0 +1 @@
deny from all

37
federated.php Normal file
View File

@ -0,0 +1,37 @@
<?php include ('header.php'); ?>
<main id="main" class="federated">
<div class="article_wrap">
<aside class="left_column">
<?php include dirname(__FILE__).('/widgets/side_current_user.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_load_options.php'); ?>
</aside>
<article class="center_column">
<header class="timeline_header">
<?php include dirname(__FILE__).('/widgets/create_status.php'); ?>
</header>
<div id="js-stream_update">
<button>
View <span></span> new Toots
</button>
</div>
<ul id="js-timeline" class="timeline">
</ul>
<footer id="js-timeline_footer" class="timeline_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
<aside class="right_column">
<section class="side_widgets_wrap">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
</section>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
</div>
</main>
<script>
current_file = location.pathname;
setTimeline("timelines/public");
$("#federated_nav").addClass('view');
$('title').text('Halcyon / Federated');
</script>
<?php include ('footer.php'); ?>

View File

@ -1,76 +1,52 @@
<!-- FOOTER -->
<footer id="footer">
<!-- Be enjoying your Mastodon!-->
</footer>
<?php include dirname(__FILE__).('/widgets/overlay_message.php'); ?>
<div id="js-overlay_content_wrap">
<div id="js-overlay_content">
<div class="temporary_object">
</div>
<div class="parmanent_object">
<?php include dirname(__FILE__).('/widgets/overlay_create_status.php'); ?>
<?php include dirname(__FILE__).('/widgets/overlay_single_reply.php'); ?>
<?php include dirname(__FILE__).('/widgets/overlay_copy_link.php'); ?>
</div>
<button class="close_button"><i class="fa fa-times" aria-hidden="true"></i></button>
</div>
<div id="js-overlay_content">
<div class="temporary_object">
</div>
<div class="parmanent_object">
<?php include dirname(__FILE__).('/widgets/overlay_create_status.php'); ?>
<?php include dirname(__FILE__).('/widgets/overlay_single_reply.php'); ?>
<?php include dirname(__FILE__).('/widgets/overlay_copy_link.php'); ?>
</div>
<button class="close_button"><i class="fa fa-times" aria-hidden="true"></i></button>
</div>
</div>
<script>
<?php if (isset($_GET['status'])): ?>
setOverlayStatus('<?php echo $_GET['status']; ?>');
<?php endif; ?>
setCurrentProfile();
badges_update();
$('.header_settings_link').attr('href','https://'+current_instance+'/settings/preferences');
$('.footer_widget_about').attr('href','https://'+current_instance+'/about');
$('.footer_widget_instance').attr('href','https://'+current_instance+'/about/more');
$('.footer_widget_terms').attr('href','https://'+current_instance+'/terms');
<?php if (isset($_GET['status'])): ?>
setOverlayStatus('<?php echo $_GET['status']; ?>');
<?php endif; ?>
setCurrentProfile();
badges_update();
$('.header_settings_link').attr('href','https://'+current_instance+'/settings/preferences');
$('.footer_widget_about').attr('href','https://'+current_instance+'/about');
$('.footer_widget_instance').attr('href','https://'+current_instance+'/about/more');
$('.footer_widget_terms').attr('href','https://'+current_instance+'/terms');
</script>
<script>
const what_to_follow_0 = JSON.parse(localStorage.getItem("what_to_follow_0"));
const what_to_follow_1 = JSON.parse(localStorage.getItem("what_to_follow_1"));
const what_to_follow_2 = JSON.parse(localStorage.getItem("what_to_follow_2"));
$('.what_to_follow_0 > .icon_box img').attr('src', what_to_follow_0.avatar);
$('.what_to_follow_0 .label_box > a').attr('href', getRelativeURL(what_to_follow_0.url, what_to_follow_0.id) );
$('.what_to_follow_0 .label_box > a > h3 .dn').text(what_to_follow_0.display_name);
$('.what_to_follow_0 .label_box > a > h3 .un').text('@'+what_to_follow_0.username);
$('.what_to_follow_0 .label_box > .follow_button').attr('mid', what_to_follow_0.id);
$('.what_to_follow_0 .label_box > .follow_button').attr('data', what_to_follow_0.url);
$('.what_to_follow_1 > .icon_box img').attr('src', what_to_follow_1.avatar);
$('.what_to_follow_1 .label_box > a').attr('href', getRelativeURL(what_to_follow_1.url, what_to_follow_1.id) );
$('.what_to_follow_1 .label_box > a > h3 .dn').text(what_to_follow_1.display_name);
$('.what_to_follow_1 .label_box > a > h3 .un').text('@'+what_to_follow_1.username);
$('.what_to_follow_1 .label_box > .follow_button').attr('mid', what_to_follow_1.id);
$('.what_to_follow_0 .label_box > .follow_button').attr('data', what_to_follow_1.url);
$('.what_to_follow_2 > .icon_box img').attr('src', what_to_follow_2.avatar);
$('.what_to_follow_2 .label_box > a').attr('href', getRelativeURL(what_to_follow_2.url, what_to_follow_2.id) );
$('.what_to_follow_2 .label_box > a > h3 .dn').text(what_to_follow_2.display_name);
$('.what_to_follow_2 .label_box > a > h3 .un').text('@'+what_to_follow_2.username);
$('.what_to_follow_2 .label_box > .follow_button').attr('mid', what_to_follow_2.id);
$('.what_to_follow_0 .label_box > .follow_button').attr('data', what_to_follow_2.url);
replace_emoji();
</script>
</body>
</html>

125
header.php Normal file
View File

@ -0,0 +1,125 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Halcyon</title>
<link rel="shortcut icon" href="/assets/images/favicon.ico">
<link rel="stylesheet" href="/assets/css/style.css" media="all">
<link rel="stylesheet" href="//cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" media="all">
<script src="//yastatic.net/jquery/3.2.1/jquery.min.js"></script>
<script src="/assets/js/halcyon/halcyonFunctions.js"></script>
<script src="/assets/js/mastodon.js/mastodon.js"></script><!-- thx @kirschn -->
<script src="/assets/js/jquery-cookie/src/jquery.cookie.js"></script>
<script src="/assets/js/shortcut.js"></script>
<script src="/assets/js/replace_emoji.js"></script>
<script src="/assets/js/halcyon/halcyonUI.js"></script>
<script src="//cdn.staticfile.org/twemoji/2.2.5/twemoji.min.js"></script>
<script>
if (
!localStorage.getItem("current_id") |
!localStorage.getItem("current_instance") |
!localStorage.getItem("current_authtoken")
){
location.href = "/login";
} else {
if( $.cookie("session") === "true" ) {
refreshApp();
} else if ( $.cookie("session") === undefined ) {
resetApp();
}
}
</script>
</head>
<body>
<header id="header">
<div class="header_nav_wrap">
<nav class="header_left_box">
<ul class="header_nav_list">
<li id="header_nav_item_home" class="header_nav_item">
<a href="/" id="home_nav">
<i class="fa fa-fw fa-home"></i>
<span>Home</span>
</a>
<div class="home_badge nav_badge invisible"></div>
</li>
<li id="header_nav_item_local" class="header_nav_item local_nav">
<a href="/local" id="local_nav">
<i class="fa fa-fw fa-users"></i>
<span>Local</span>
</a>
<div class="local_badge nav_badge invisible"></div>
</li>
<li id="header_nav_item_federated" class="header_nav_item federated_nav">
<a href="/federated" id="federated_nav">
<i class="fa fa-fw fa-globe"></i>
<span>Federated</span>
</a>
<div class="federated_badge nav_badge invisible"></div>
</li>
<li id="header_nav_item_notifications" class="header_nav_item notifications_nav">
<a href="/notifications" id="notifications_nav">
<i class="fa fa-fw fa-bell"></i>
<span>Notifications</span>
</a>
<div class="notification_badge nav_badge invisible"></div>
</li>
</ul>
</nav>
<div class="header_center_box">
<h1 class="header_nav_item mastodon_logo logo_box">
<a href="/">
<img src="/assets/images/mastodon.svg" alt="Halcyon for Mastodon">
</a>
</h1>
</div>
<nav class="header_right_box">
<ul class="header_nav_list">
<li class="header_nav_item serch_form_wrap">
<form class="search_form" action="/search" method="GET">
<input id="search_form" class="search_form_input" placeholder="Search Mastodon" type="text" name="q" accesskey="/">
<span class="search_form_submit">
<button type="submit">
<i class="fa fa-fw fa-search"></i>
</button>
</span>
</form>
</li>
<li class="header_nav_item my_account_wrap">
<button class="header_account_avatar">
<div class="my_account">
<img class="js_current_profile_image" />
</div>
</button>
<nav class="header_my_account_nav invisible">
<ul>
<li>
<a class="js_current_profile_link emoji_poss">
<span class="js_current_profile_displayname display_name"></span>
<span>View profile</span>
</a>
</li>
</ul>
<ul>
<li>
<a class="header_settings_link" href="">Settings</a>
</li>
<li>
<a href="/logout">Log out</a>
</li>
</ul>
</nav>
</li>
<li class="header_nav_item toot_button_wrap">
<button id="creat_status" class="toot_button" accesskey="n">
<div class="toot_button_label">
<i class="fa fa-fw fa-pencil-square-o"></i>
<span>Toot</span>
</div>
</button>
</li>
</ul>
</nav>
</div>
</header>

37
home.php Normal file
View File

@ -0,0 +1,37 @@
<?php include ('header.php'); ?>
<main id="main" class="home">
<div class="article_wrap">
<aside class="left_column">
<?php include dirname(__FILE__).('/widgets/side_current_user.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_load_options.php'); ?>
</aside>
<article class="center_column">
<header class="timeline_header">
<?php include dirname(__FILE__).('/widgets/create_status.php'); ?>
</header>
<div id="js-stream_update">
<button>
View <span></span> new Toots
</button>
</div>
<ul id="js-timeline" class="timeline">
</ul>
<footer id="js-timeline_footer" class="timeline_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
<aside class="right_column">
<section class="side_widgets_wrap">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
</section>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
</div>
</main>
<script>
current_file = location.pathname;
setTimeline("timelines/home");
$("#home_nav").addClass('view');
$('title').text('Halcyon');
</script>
<?php include ('footer.php'); ?>

44
local.php Normal file
View File

@ -0,0 +1,44 @@
<?php include ('header.php'); ?>
<main id="main">
<div class="article_wrap">
<aside class="left_column">
<?php include dirname(__FILE__).('/widgets/side_current_user.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_load_options.php'); ?>
</aside>
<article class="center_column">
<header class="timeline_header">
<?php include dirname(__FILE__).('/widgets/create_status.php'); ?>
</header>
<div id="js-stream_update">
<button>
View <span></span> new Toots
</button>
</div>
<ul id="js-timeline" class="timeline">
</ul>
<footer id="js-timeline_footer" class="timeline_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
<aside class="right_column">
<section class="side_widgets_wrap">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
</section>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
</div>
</main>
<script>
current_file = location.pathname;
if (
localStorage.getItem("setting_local_instance") === "default" |
localStorage.getItem("setting_local_instance") === current_instance
) {
setTimeline("timelines/public", [{name:"local",data:"ture"}]);
} else {
setOtherTimeline(localStorage.getItem("setting_local_instance")+"/api/v1/", [{name:"local",data:"ture"}]);
}
$("#local_nav").addClass('view');
$('title').text('Halcyon / Local');
</script>
<?php include ('footer.php'); ?>

451
login/assets/css/style.css Normal file
View File

@ -0,0 +1,451 @@
@charset "utf-8";
* {
margin: 0;
padding: 0;
font-size: 100%;
}
a {
text-decoration: none;
word-break: break-all;
color: inherit;
}
a:hover {
text-decoration: underline;
}
ul, ol {
list-style: none;
padding: 0;
margin: 0;
}
img {
vertical-align: top;
border: 0;
max-width: 100%;
max-height: 100%;
}
button {
font-size: 100%;
}
.clear {
clear: both;
}
.red {
color: red!important;
}
.invisible {
display: none!important;
}
.no-events {
pointer-events: none!important;
}
.no-underline,
.no-underline:hover {
text-decoration: none!important;
}
.disallow_select {
user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
}
.text_ellipsis {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.pointer {
cursor: pointer;
}
.khmer_font {
font-family: "Khmer MN", Helvetica, Arial, sans-serif!important;
}
.gill_font {
font-family: "Gill Sans", Helvetica, Arial, sans-serif!important;
}
.trebuchet_font {
font-family: "Trebuchet MS", Helvetica, Arial, sans-serif!important;
}
h1, h2, h3, h4, h5, h6 {
font-weight: normal;
line-height: 1;
margin: 0;
padding: 0;
}
blockquote, q {
quotes: none;
margin: 0;
}
blockquote * {
margin: 0;
word-break: break-all;
}
blockquote:before, blockquote:after,
q:before, q:after {
content:'';
content:none;
}
article,aside,details,figcaption,figure,
footer,header,hgroup,menu,nav,section {
display:block;
}
textarea {
width: 100%;
}
input {
max-width: 100%;
}
button,
input[type="submit"],
input[type="button"],
input[type="text"],
input[type="password"],
textarea,
select{
background-color: transparent;
border: none;
cursor: pointer;
outline: none;
padding: 0;
appearance: none;
}
input:-webkit-autofill {
-webkit-box-shadow: 0 0 0px 1000px transparent inset;
}
img.emoji {
height: 1em;
width: 1em;
margin: 0 .05em 0 .1em;
vertical-align: -0.1em;
}
html {
font-family : "Trebuchet MS",Helvetica,Arial,sans-serif;
font-size : 100%;
line-height : 1;
color: #333;
min-width: 100%;
min-height: 100%;
}
body {
margin: 0;
padding: 0;
min-width: 100%;
min-height: 100%;
word-wrap:break-word;
background-color: #F5F8FA;
}
#header {
width: 100%;
height: 56px;
color: #fff;
background-color: #222;
box-shadow: 0px 3px 5px rgba(0,0,0,0.26);
position: fixed;
z-index: 999;
}
#header #header_wrap {
display: flex;
justify-content: flex-start;
align-items: center;
width: 100%;
height: 100%;
}
#header #header_wrap > .header_box {
height: 100%;
flex-grow: 1;
flex-shrink: 0;
}
#header #header_wrap .header_box.header_right_box {
display: flex;
justify-content: flex-start;
}
#header #header_wrap .header_box.header_right_box .title_box {
height: 100%;
margin-left: 24px;
box-sizing: border-box;
}
#header #header_wrap .header_box.header_left_box {
display: flex;
justify-content: flex-end;
}
#header #header_wrap .header_box.header_left_box nav {
height: 100%;
}
#header #header_wrap .header_box.header_left_box .nav_box ul {
display: block;
height: 100%;
width: 100%;
}
#header #header_wrap .header_box.header_left_box .nav_box ul a {
height: 100%;
}
#header #header_wrap .header_box.header_left_box .nav_box ul li {
display: block;
float: left;
cursor: pointer;
height: calc(100% - 5px*2 );
margin-top: 5px;
border-bottom: 0px solid #007BD0;
}
#header #header_wrap .header_box.header_left_box .nav_box ul li span {
display: block;
height: 100%;
margin: auto;
padding: 15px 24px;
font-size: 14px;
box-sizing: border-box;
}
#header #header_wrap .header_box.header_left_box .nav_box ul li span i {
margin-right: 4px;
}
#header #header_wrap .header_box.header_left_box .nav_box ul li:hover {
color: #189EFC;
border-bottom-width: 5px;
transition: 0.15s ease-out;
}
#main {
padding-top: 56px;
}
#main #login_form_wrap {
width: 100%;
height: 560px;
padding: 56px 0;
margin-bottom: -200px;
box-sizing: border-box;
background-image: url("/login/assets/images/background.jpg");
background-size: cover;
background-repeat: no-repeat;
}
#main #login_form_wrap .login_form {
position: relative;
width: 640px;
height: 220px;
padding: 36px 24px;
margin: auto;
overflow: hidden;
background: inherit;
box-sizing: border-box;
border-radius: 4px;
border: 1px solid #C9EFF8;
text-align: center;
box-shadow: 0px 5px 5px rgba(0,0,0,0.26);
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form.expand {
width: 780px;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form::before {
display: block;
position: absolute;
content: "";
top: -3px;
left: -3px;
right: -3px;
bottom: -3px;
background: inherit;
background-position: top center;
filter: blur(3px);
border-radius: 5px;
z-index: 0;
}
#main #login_form_wrap .login_form form {
position: relative;
margin: auto;
z-index: 1;
color: #C9EFF8;
}
#main #login_form_wrap .login_form form a {
color: #fff;
}
#main #login_form_wrap .login_form h2 {
font-size: 32px;
font-weight: 600;
margin-bottom: 16px;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form.expand h2 {
font-size: 42px;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form p {
margin-bottom: 16px;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form.expand p {
opacity: 0;
margin-bottom: 0;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form .login_form_main {
display: flex;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
margin: auto;
height: 32px;
width: 276px;
border: 1px solid #C9EFF8;
border-radius: 32px;
background-color: rgba(0,0,0,.3);
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form.expand .login_form_main {
width: 360px;
height: 42px;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form .login_form_main.active {
box-shadow: 0px 3px 5px rgba(0,0,0,0.26);
}
#main #login_form_wrap .login_form .login_form_main input[name="acct"] {
display: block;
-webkit-appearance : none;
flex-grow: 1;
padding: 4px 0 4px 14px;
color: #C9EFF8;
border: none;
background: none;
box-sizing: border-box;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form.expand .login_form_main input[name="acct"]{
flex-grow: 2;
padding: 8px 0 8px 14px;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form .login_form_main .login_form_continue {
display: block;
flex-grow: 1;
color: #C9EFF8;
}
#main #login_form_wrap .login_form .login_form_main .login_form_continue:hover {
color: #fff;
}
#main #login_form_wrap .login_form .login_form_agree {
margin: 16px auto 0;
}
#main #login_form_wrap .login_form .login_form_agree i {
color: #fff;
}
#article {
position: relative;
width: 640px;
margin: auto;
margin-bottom: 56px;
padding: 24px 36px 36px;
border-radius: 4px;
background-color: #fff;
box-sizing: border-box;
box-shadow: 3px 3px 5px rgba(0,0,0,0.26);
}
#article h2 {
font-size: 32px;
font-weight: 600;
margin: 16px 0;
}
#article p {
display: inline-block;
margin-bottom: 16px;
font-size: 16px;
line-height: 1.2;
}
#article .image_wrap {
display: block;
position: relative;
margin: 0 -36px 24px;
border-top: 0.5px solid #555;
border-bottom: 0.5px solid #555;
}
#article .image_wrap ul {
display: block;
position: relative;
width: 100%;
height: 370px;
overflow: hidden;
}
#article .image_wrap ul li {
position: absolute;
top: 0;
left: 0;
}
@keyframes fadeout {
0% {opacity: 1;}
100% {opacity: 0;}
}
@keyframes fadein {
0% {opacity: 0;}
100% {opacity: 1;}
}
#article .image_wrap ul li.fadeout {
animation-name: fadeout;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
#article .image_wrap ul li.fadein {
animation-name: fadein;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
#article .image_wrap .switch_button {
display: block;
opacity: 0;
position: absolute;
top: 0;
width: 30px;
height: 100%;
color: #fff;
background-color: rgba(0, 0, 0, .3);
transition: 0.15s ease-out;
}
#article .image_wrap:hover .switch_button {
opacity: 1;
transition: 0.15s ease-out;
}
@keyframes switching_image_list {
0% {background-color: rgba(0, 0, 0, .3);}
50% {background-color: rgba(0, 0, 0, .8);}
100% {background-color: rgba(0, 0, 0, .3);}
}
#article .image_wrap:hover .switch_button.active {
animation-name: switching_image_list;
animation-duration: 0.35s;
}
#article .image_wrap .switch_button.prev_button {
left: 0;
}
#article .image_wrap .switch_button.next_button {
right: 0;
}
#article a {
color: #189EFC;
}
#footer {
width: 640px;
padding: 24px 36px 12px;
box-sizing: border-box;
margin: auto;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
box-shadow: 3px 3px 5px rgba(0,0,0,0.26);
background-color: #222;
}
#footer .footer_anchor {
display: flex;
justify-content: center;
align-items: center;
color: #444;
font-size: 36px;
transition: 0.15s ease-out;
}
#footer .footer_anchor:hover {
color: #555;
transition: 0.15s ease-out;
}
#footer span {
font-size: 14px;
color: #ddd;
margin: auto;
display: block;
text-align: center;
}

View File

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 129 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 510 KiB

After

Width:  |  Height:  |  Size: 510 KiB

View File

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 156 KiB

View File

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 134 KiB

View File

@ -0,0 +1,43 @@
$(function() {
$(document).on('change','.login_form_agree #agree', function(e) {
const icon = $(this).parent().find('i.fa');
if ( $(this).prop('checked') ) {
icon.addClass("fa-check-square-o");
icon.removeClass("fa-square-o");
} else if ( !$(this).prop('checked') ) {
icon.addClass("fa-square-o");
icon.removeClass("fa-check-square-o");
}
});
$(document).on('focus', '#main #login_form_wrap .login_form .login_form_main input[name="acct"]', function(e) {
$(this).parent().addClass('active')
$(".login_form").addClass('expand');
})
$(document).on('blur', '#main #login_form_wrap .login_form .login_form_main input[name="acct"]', function(e) {
$(this).parent().removeClass('active')
$(".login_form").removeClass('expand');
})
$(document).on('mousedown', '.image_wrap .switch_button', function(e) {
const self = $(this);
self.addClass('active');
setTimeout(function() {
self.removeClass('active');
}, 500);
})
$(document).on('click', '.image_wrap .prev_button', function(e) {
const firstChild = $(this).parent(".image_wrap").find('ul li:first-child');
firstChild.appendTo(".image_wrap ul");
firstChild.addClass('fadein');
setTimeout(function() {
firstChild.removeClass('fadein');
}, 500);
})
$(document).on('click', '.image_wrap .next_button', function(e) {
const lastChild = $(this).parent(".image_wrap").find('ul li:last-child');;
lastChild.addClass('fadeout');
setTimeout(function() {
lastChild.prependTo(".image_wrap ul");
lastChild.removeClass('fadeout');
}, 500);
})
})

49
login/auth.php Normal file
View File

@ -0,0 +1,49 @@
<!DOCTYPE HTML>
<html lang='en'>
<head>
<script>
if(
localStorage.getItem('current_id') |
localStorage.getItem('current_instance') |
localStorage.getItem('current_authtoken')
){
location.href = '/logout';
};
</script>
<?php
require_once('../authorize/mastodon.php');
use HalcyonSuite\HalcyonForMastodon\Mastodon;
use Exception;
$api = new Mastodon();
if ($_GET['code']) {
$domain = htmlspecialchars((string)filter_input(INPUT_GET, 'host'), ENT_QUOTES);
$URL= 'https://'.$domain;
$api->selectInstance($URL);
$response = $api->get_access_token($api->clientWebsite.'/auth?&host='.$domain, htmlspecialchars((string)filter_input(INPUT_GET, 'code'), ENT_QUOTES));
if ($response['html']["access_token"]) {
$access_token = $response['html']["access_token"];
$account_id = $api->accounts_verify_credentials()['html']['id'];
echo "
<script>
localStorage.setItem('current_id','$account_id');
localStorage.setItem('current_instance','$domain');
localStorage.setItem('current_authtoken', '$access_token');
localStorage.setItem('setting_post_stream', 'manual');
localStorage.setItem('setting_post_privacy', 'public');
localStorage.setItem('setting_local_instance', 'default');
localStorage.setItem('setting_search_filter', 'all');
localStorage.setItem('what_to_follow_0', JSON.stringify({id:'',username:'Halcyon',display_name:'Halcyon for Mastodon',url:'https://social.csswg.org/@halcyon',avatar:'https://social.csswg.org/system/accounts/avatars/000/005/666/original/e9a158381ce1249a.png'}));
localStorage.setItem('what_to_follow_1', JSON.stringify({id:'',username:'Gargron',display_name:'Eugen',url:'https://mastodon.social/@Gargron',avatar:'https://files.mastodon.social/accounts/avatars/000/000/001/original/4df197532c6b768c.png'}));
localStorage.setItem('what_to_follow_2', JSON.stringify({id:'',username:'Mastodon',display_name:'Mastodon',url:'https://mastodon.social/@Mastodon',avatar:'https://files.mastodon.social/accounts/avatars/000/013/179/original/27bc451c7713091b.jpg'}));
location.href = '/';
</script>
";
}
}
?>
<script src="//yastatic.net/jquery/3.2.1/jquery.min.js"></script>
<script src="/assets/js/mastodon.js/mastodon.js"></script>
</head>
<body>
</body>
</html>

170
login/login.php Normal file
View File

@ -0,0 +1,170 @@
<?php
require_once('../authorize/mastodon.php');
use HalcyonSuite\HalcyonForMastodon\Mastodon;
use Exception;
if (isset($_POST['acct'])) {
$domain = explode("@", mb_strtolower(htmlspecialchars((string)filter_input(INPUT_POST, 'acct'), ENT_QUOTES)))[2];
$URL= 'https://'.$domain;
$api= new Mastodon();
if ( !preg_match('/(^[a-z0-9\-\.\/]+?\.[a-z0-9-]+$)/', $domain) ) {
header('Location: '.$api->clientWebsite.'/login?cause=domain', true, 303);
die();
} else {
try {
$client_id = $api->getInstance($URL)["client_id"];
$authorizeURL= $URL.'/oauth/authorize?client_id='.$client_id.'&response_type=code&scope=read+write+follow&website='.$api->clientWebsite.'&redirect_uri='.urlencode($api->clientWebsite.'/auth?&host='.$domain);
header("Location: {$authorizeURL}", true, 303);
die();
} catch (Exception $e) {
header('Location: '.$api->clientWebsite.'/login?cause=domain', true, 303);
die();
}
}
}
?>
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Halcyon for Mastodon</title>
<link rel="shortcut icon" href="/assets/images/favicon.ico">
<link rel="stylesheet" href="/login/assets/css/style.css" media="all">
<link rel="stylesheet" href="//cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" media="all">
<script src="//yastatic.net/jquery/3.2.1/jquery.min.js"></script>
<script src="/assets/js/jquery-cookie/src/jquery.cookie.js"></script>
<script src="/login/assets/js/halcyon_login.js"></script>
<script>
if(
localStorage.getItem("current_id") |
localStorage.getItem("current_instance") |
localStorage.getItem("current_authtoken")
){
location.href = "/";
};
</script>
</head>
<body>
<header id="header">
<div id="header_wrap">
<div id="header_title_wrap" class="header_box header_right_box">
<div class="header_box_child title_box">
<a href="/">
<img src="/login/assets/images/halcyon-title.png" alt="Halcyon for mastodon">
</a>
</div>
</div>
<div id="header_menu_wrap" class="header_box header_left_box">
<nav class="header_box_child nav_box">
<ul>
<a href="https://social.csswg.org/@halcyon" class="no-underline">
<li>
<span><i class="fa fa-newspaper-o" aria-hidden="true"></i>News</span>
</li>
</a>
<a href="https://github.com/halcyon-suite/halcyon" class="no-underline">
<li>
<span><i class="fa fa-code" aria-hidden="true"></i>Source</span>
</li>
</a>
<a class="no-underline">
<li>
<span><i class="fa fa-balance-scale" aria-hidden="true"></i>Terms</span>
</li>
</a>
<a href="http://www.nikisoft.one/contact.php" class="no-underline">
<li>
<span><i class="fa fa-envelope" aria-hidden="true"></i>Contact</span>
</li>
</a>
<a href="#login_form_wrap" class="no-underline">
<li>
<span><i class="fa fa-user-circle-o" aria-hidden="true"></i>Login</span>
</li>
</a>
</ul>
</nav>
</div>
</div>
</header>
<main id="main">
<div id="login_form_wrap">
<div class="login_form">
<form method="POST" >
<h2>Login to Halcyon</h2>
<p>
or <a href="https://joinmastodon.org/">create an account</a>
</p>
<div class="session_aleart">
<span></span>
</div>
<div class="login_form_main">
<input name="acct" type="text" class="login_form_input" placeholder="johndoe@example.com" required>
<label class="login_form_continue pointer">
<i class="fa fa-chevron-circle-right" aria-hidden="true"></i>
<input id="login_continue" type="submit" value="" class="invisible"></input>
</label>
</div>
<div class="login_form_agree">
<label class="login_form_agree_check disallow_select pointer">
<i class="fa fa-check-square-o" aria-hidden="true"></i>
I agree with the <a href="/terms">Terms</a>
<input id="agree" type="checkbox" required checked class="invisible"/>
</label>
</div>
</form>
</div>
</div>
<article id="article">
<h2>What is Halcyon</h2>
<p>
Halcyon is standard <span style="font-weight: bold">Twitter like client</span> of Mastodon, And you can use it just by login to your instance. Let's Toot like a tweet.
</p>
<div class="image_wrap">
<ul>
<li><img src="/login/assets/images/preview2.png" alt="halcyon_screenshot"/></li>
<li><img src="/login/assets/images/preview1.png" alt="halcyon_screenshot"/></li>
<li><img src="/login/assets/images/preview0.png" alt="halcyon_screenshot"/></li>
</ul>
<button class="prev_button switch_button"><i class="fa fa-angle-left" aria-hidden="true"></i></button>
<button class="next_button switch_button"><i class="fa fa-angle-right" aria-hidden="true"></i></button>
</div>
<h2>Contact / Feedback</h2>
<p>
Mastodon: <a href="https://social.csswg.org/@halcyon" target="_blank">halcyon@social.csswg.org</a><br />
Email: <a href="http://www.nikisoft.one/contact.php" target="_blank">Use my contact form</a><br />
Github: <a href="https://github.com/halcyon-suite/halcyon" target="_blank">halcyon-suite/halcyon</a>
</p>
<h2>Help us</h2>
<p>
Bitcoin: 1D6GThQqHQYnruKYrKyW9JC86ZGWxjt1hK<br />
</p>
</article>
</main>
<!-- FOOTER -->
<footer id="footer">
<div class="footer_anchor">
<a href="#">
<i class="fa fa-angle-up" aria-hidden="true"></i>
</a>
</div>
<span>Photo by <a href="https://www.flickr.com/photos/95387826@N08/">Michio Morimoto on Flickr</a> (CC BY 2.0)</span>
</footer>
</body>
<?php if (isset($_GET['cause'])): ?>
<script>
$(function() {
var cause = "<?= htmlspecialchars((string)filter_input(INPUT_GET, 'cause'), ENT_QUOTES) ?>";
if ( cause === "domain" ) {
$('.login_form_main').addClass('error');
$('.session_aleart').removeClass('invisible');
$('.session_aleart > span').text('This instance does not exsist.');
}
});
$(document).on('click','.login_form_main', function(e) {
$(this).removeClass('error');
});
</script>
<?php endif; ?>
</html>

View File

@ -1,3 +1,3 @@
<script src="//yastatic.net/jquery/3.2.1/jquery.min.js"></script>
<script src="/assets/js/jquery-cookie/src/jquery.cookie.js"></script>
<script>localStorage.clear();$.removeCookie('session');location.href="/login";</script>
<script>localStorage.clear();$.removeCookie('session');location.href="/login";</script>

100
login/terms.php Normal file
View File

@ -0,0 +1,100 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Halcyon for Mastodon</title>
<link rel="shortcut icon" href="/assets/images/favicon.ico">
<link rel="stylesheet" href="/login/assets/css/style.css" media="all">
<link rel="stylesheet" href="//cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" media="all">
<script src="//yastatic.net/jquery/3.2.1/jquery.min.js"></script>
<script src="/assets/js/jquery-cookie/src/jquery.cookie.js"></script>
<script src="/login/assets/js/halcyon_login.js"></script>
</head>
<body>
<header id="header">
<div id="header_wrap">
<div id="header_title_wrap" class="header_box header_right_box">
<div class="header_box_child title_box">
<a href="/">
<img src="/login/assets/images/halcyon-title.png" alt="Halcyon for mastodon"/>
</a>
</div>
</div>
<div id="header_menu_wrap" class="header_box header_left_box">
<nav class="header_box_child nav_box">
<ul>
<a href="https://social.csswg.org/@halcyon" class="no-underline">
<li>
<span><i class="fa fa-newspaper-o" aria-hidden="true"></i>News</span>
</li>
</a>
<a href="https://github.com/halcyon-suite/halcyon" class="no-underline">
<li>
<span><i class="fa fa-code" aria-hidden="true"></i>Source</span>
</li>
</a>
<a class="no-underline">
<li>
<span><i class="fa fa-balance-scale" aria-hidden="true"></i>Terms</span>
</li>
</a>
<a href="http://www.nikisoft.one/contact.php" class="no-underline">
<li>
<span><i class="fa fa-envelope" aria-hidden="true"></i>Contact</span>
</li>
</a>
<a href="#login_form_wrap" class="no-underline">
<li>
<span><i class="fa fa-user-circle-o" aria-hidden="true"></i>Login</span>
</li>
</a>
</ul>
</nav>
</div>
</div>
</header>
<main id="main">
<article id="article">
<h1>Halcyon Terms of Use</h1>
<p class="description">This terms of use agreement is for the users of web service Halcyon for Mastodon (Halcyon for short) hosted at <a href="http://example.com">example.com</a>.</p>
<br/>
<h2>1. Agreement</h2>
<p>By logging into Halcyon you agree to this terms of use agreement. Do not use this service if you do not agree to these terms.</p>
<br/>
<h2>2. Change</h2>
<p>We reserve the right to modify these terms of use at any time if deemed necessary.</p>
<br/>
<h2>3. Account</h2>
<p>Users can connect to various Mastodon accounts from Halcyon, and Halcyon will not interfere with those connection.</p>
<br/>
<h2>4. Content</h2>
<p>Halcyon does not own the right to or hold responsibility for any text, image, animation, audio content accessible from Halcyon. The right and responsibility belong to the owners of instances that host those content.</p>
<br/>
<h2>5. Guideline</h2>
<p>Halcyon reserves the right to terminate service for</p>
<ul>
<li>actions violating the laws of countries</li>
<li>actions contrary to public order and standards of decency</li>
<li>violation of third partys right to intellectual property, brand, privacy, etc.</li>
<li>acts of violence, sexual nature, of discrimination</li>
<li>phishing or spamming</li>
<li>actions causing problem to the network infrastructure of Halcyon</li>
</ul>
<br/>
<h2>6. Disclaimer</h2>
<p>Halcyon is not responsible for any damage caused by using this service.</p>
<br/>
<p>Last updated 2017/5/12</p>
</article>
</main>
<footer id="footer">
<div class="footer_anchor">
<a href="#">
<i class="fa fa-angle-up" aria-hidden="true"></i>
</a>
</div>
<span>Photo by <a href="https://www.flickr.com/photos/95387826@N08/">Michio Morimoto on Flickr</a> (CC BY 2.0)</span>
</footer>
</body>

42
notifications.php Normal file
View File

@ -0,0 +1,42 @@
<?php include ('header.php'); ?>
<main id="main">
<div class="article_wrap">
<aside class="left_column">
</aside>
<article class="center_column">
<header class="timeline_header">
<ul class="header_items">
<li class="item toots view">
<a href="#">
All
</a>
</li>
</ul>
</header>
<div id="js-stream_update">
<button>
View <span></span> new notitification
</button>
</div>
<ul id="js-timeline" class="timeline">
</ul>
<footer id="js-timeline_footer" class="timeline_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
<aside class="right_column">
<section class="side_widgets_wrap">
<?php include dirname(__FILE__).('/widgets/side_what_to_follow.php'); ?>
</section>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
</div>
</main>
<script>
current_file = location.pathname;
$("#notifications_nav").addClass('view');
localStorage.setItem("notification_count", 0);
setNotifications();
$('title').text('Halcyon / Notifications')
</script>
<?php include ('footer.php'); ?>

View File

@ -1,25 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Halcyon / ?</title>
<link rel="shortcut icon" href="/assets/images/favicon.ico" />
<link rel="stylesheet" type="text/css" href="/assets/css/404.css" media="all" />
</head>
<body>
<article>
<h1>404</h1>
<h2>Sorry, something went wrong.</h2>
</article>
</body>
</html>

View File

@ -1,169 +0,0 @@
@charset "utf-8";
/*--------------------------------------
Reset
--------------------------------------*/
* {
margin: 0;
padding: 0;
font-size: 100%;
}
a {
text-decoration: none;
word-break: break-all;
color: inherit;
}
a:hover {
text-decoration: underline;
}
ul, ol {
list-style: none;
padding: 0;
margin: 0;
}
img {
vertical-align: top;
border: 0;
max-width: 100%;
max-height: 100%;
}
button {
font-size: 100%;
}
.clear {
clear: both;
}
.red {
color: red!important;
}
.invisible {
display: none!important;
}
.no-events {
pointer-events: none;
}
.disallow_select {
user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
}
.text_ellipsis {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
h1, h2, h3, h4, h5, h6 {
font-weight: normal;
line-height: 1;
margin: 0;
padding: 0;
}
blockquote, q {
quotes: none;
margin: 0;
}
blockquote * {
margin: 0;
word-break: break-all;
}
blockquote:before, blockquote:after,
q:before, q:after {
content:'';
content:none;
}
article,aside,details,figcaption,figure,
footer,header,hgroup,menu,nav,section {
display:block;
}
textarea {
width: 100%;
}
input {
max-width: 100%;
}
button, input[type="submit"], input[type="button"]{
background-color: transparent;
border: none;
cursor: pointer;
outline: none;
padding: 0;
appearance: none;
}
/* Twitter Emoji Prefix */
img.emoji {
height: 1em;
width: 1em;
margin: 0 .05em 0 .1em;
vertical-align: -0.1em;
}
.emoji_poss .auth_emoji {
display: inline-block;
height: 100%;
margin: auto;
margin-left: 4px;
}
/*--------------------------------------
Base
--------------------------------------*/
html {
font-family : "Helvetica Neue",Helvetica,"ヒラギノ角ゴ Pro W3",
"Hiragino Kaku Gothic Pro",Meiryo,"メイリオ"," Pゴシック",Arial,sans-serif;
font-size : 100%;
line-height : 1;
color: #333;
min-width: 100%;
min-height: 100%;
}
body {
margin: 0;
padding: 0;
min-width: 100%;
min-height: 100%;
word-wrap:break-word;
background-color: #189EFC;
}
article {
margin: auto;
padding: 24px;
}
h1 {
font-size: 248px;
text-align: center;
color: #fff;
font-weight: 600;
}
h2 {
font-size: 56px;
text-align: center;
color: #fff;
font-weight: 200;
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,258 +0,0 @@
/*-----------------------------------
get Link from XHR Header
-----------------------------------*/
function getLinkFromXHRHeader(xhrheaderstring) {
const re = xhrheaderstring.match(/link: <.+api\/v1\/(.+?)>; rel="(.+?)", <.+api\/v1\/(.+?)>; rel="(.+?)"/);
let di = new Object();
if(re){
di[re[2]] = re[1];
di[re[4]] = re[3];
}
return di;
}
/*----------------------------------
Make relative URL
----------------------------------*/
function getRelativeURL(url, id, options) {
const array = url.split('/');
if ( array.length >= 4 ) {
if ( !options ) {
var options = ""
};
if (id) {
// IF WITHIN ID
if (array[array.length-1].substr(0,1) === '@') {
const link = '/'+array[array.length-1]+'@'+array[2]+options+'?mid='+id+'&';
return link;
} else {
const link = '/@'+array[array.length-1]+'@'+array[2]+options+'?mid='+id+'&';
return link;
}
} else {
// IF WITHOUT ID (URL ONLY)
if (array[array.length-1].substr(0,1) === '@') {
const link = '/'+array[array.length-1]+'@'+array[2]+options;
return link;
} else {
const link = '/@'+array[array.length-1]+'@'+array[2]+options;
return link;
}
}
}
}
/*-----------------------------------
Replace Mastodon link for Halcyon
-----------------------------------*/
function replaceInternalLink(){
// REPLIES
$(".h-card > a").each(function(i) {
$(this).attr('href',getRelativeURL($(this).attr('href')));
});
// HASHTAGS
$(".toot_article a").each(function(i) {
const tags = $(this).attr('href').match(/https:\/\/.+..+\/tags\/(.+)\/?/);
if (tags) {
$(this).attr('href','/search?q='+tags[1]);
}
});
}
/*-----------------------------------
Datetime exchange
-----------------------------------*/
function getConversionedDate(key, value) {
if (value === null ||
value.constructor !== String ||
value.search(/^\d{4}-\d{2}-\d{2}/g) === -1)
return value;
return new Date(value);
}
/*----------------------------------
Relative Datetime
----------------------------------*/
function getRelativeDatetime(current_time, posted_time) {
const calendar = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var posted_time_original = posted_time,
posted_time = getConversionedDate(null, posted_time_original).getTime(),
elapsedTime = Math.ceil((current_time-posted_time)/1000);
if (elapsedTime < 60) {
const datetime = "・" + elapsedTime + "s";
return datetime;
} else if (elapsedTime < 120) {
const datetime = "・1m";
return datetime;
} else if (elapsedTime < (60*60)) {
const datetime = "・" + (Math.floor(elapsedTime / 60) < 10 ? " " : "") + Math.floor(elapsedTime / 60) + "m";
return datetime;
} else if (elapsedTime < (120*60)) {
const datetime = "・1h";
return datetime;
} else if (elapsedTime < (24*60*60)) {
const datetime = "・" + (Math.floor(elapsedTime / 3600) < 10 ? " " : "") + Math.floor(elapsedTime / 3600) + "h";
return datetime;
} else {
const datetime = "・" + calendar[posted_time_original.getMonth()] + " " + posted_time_original.getDate();
return datetime;
}
}
/*-----------------------------------
ResetApp
-----------------------------------*/
function resetApp() {
/* IMPORTANT */
current_id = Number(localStorage.getItem("current_id"));
current_instance = localStorage.getItem("current_instance");
authtoken = localStorage.getItem("current_authtoken");
// Start api
api = new MastodonAPI({
instance: 'https://'+current_instance,
api_user_token: authtoken
});
// Set local storage items
api.get("accounts/verify_credentials", function(AccountObj) {
// SAVE PROFILE FOR LOCALSTORAGE (ENABLE BETWEEN ONE SESSION)
localStorage.setItem("current_display_name", AccountObj["display_name"]);
localStorage.setItem("current_acct", AccountObj["acct"]);
localStorage.setItem("current_url", getRelativeURL(AccountObj["url"],AccountObj["id"]));
localStorage.setItem("current_header", AccountObj["header"]);
localStorage.setItem("current_avatar", AccountObj["avatar"]);
localStorage.setItem("current_statuses_count", AccountObj["statuses_count"]);
localStorage.setItem("current_following_count", AccountObj["following_count"]);
localStorage.setItem("current_followers_count", AccountObj["followers_count"]);
localStorage.setItem("current_statuses_count_link", getRelativeURL(AccountObj["url"],AccountObj["id"]));
localStorage.setItem("current_following_count_link", getRelativeURL(AccountObj["url"],AccountObj["id"],'/following'));
localStorage.setItem("current_followers_count_link", getRelativeURL(AccountObj["url"],AccountObj["id"],'/followers'));
localStorage.setItem("current_favourites_link", getRelativeURL(AccountObj["url"],AccountObj["id"],'/favourites'));
// PROFILE
current_display_name = localStorage.getItem("current_display_name");
current_acct = localStorage.getItem("current_acct");
current_url = localStorage.getItem("current_url");
current_header = localStorage.getItem("current_header");
current_avatar = localStorage.getItem("current_avatar");
current_statuses_count = localStorage.getItem("current_statuses_count");
current_following_count = localStorage.getItem("current_following_count");
current_followers_count = localStorage.getItem("current_followers_count");
current_statuses_count_link = localStorage.getItem("current_statuses_count_link");
current_following_count_link = localStorage.getItem("current_following_count_link");
current_followers_count_link = localStorage.getItem("current_followers_count_link");
current_favourites_link = localStorage.getItem("current_favourites_link");
// REPLACE USER'S INFORMATIONS
$(".js_current_profile_displayname").text(current_display_name);
$(".js_current_profile_username").text(current_acct);
$(".js_current_profile_link").attr('href', current_url);
$(".js_current_header_image").attr('src', current_header);
$(".js_current_profile_image").attr('src', current_avatar);
$(".js_current_toots_count").text(current_statuses_count);
$(".js_current_following_count").text(current_following_count);
$(".js_current_followers_count").text(current_followers_count);
$(".current_toots_count_link").attr('href', current_statuses_count_link);
$(".current_following_count_link").attr('href', current_following_count_link);
$(".current_followers_count_link").attr('href', current_followers_count_link);
replace_emoji();
});
$.cookie("session", "true", { path: '/' });
}
/*-----------------------------------
RefreshApp
-----------------------------------*/
function refreshApp() {
// IMPORTANT
current_id = Number(localStorage.getItem("current_id"));
current_instance = localStorage.getItem("current_instance");
authtoken = localStorage.getItem("current_authtoken");
// Start api
api = new MastodonAPI({
instance: "https://"+current_instance,
api_user_token: authtoken
});
// PROFILE
current_display_name = localStorage.getItem("current_display_name");
current_acct = localStorage.getItem("current_acct");
current_url = localStorage.getItem("current_url");
current_header = localStorage.getItem("current_header");
current_avatar = localStorage.getItem("current_avatar");
current_statuses_count = localStorage.getItem("current_statuses_count");
current_following_count = localStorage.getItem("current_following_count");
current_followers_count = localStorage.getItem("current_followers_count");
current_statuses_count_link = localStorage.getItem("current_statuses_count_link");
current_following_count_link = localStorage.getItem("current_following_count_link");
current_followers_count_link = localStorage.getItem("current_followers_count_link");
current_favourites_link = localStorage.getItem("current_favourites_link");
}
/*-----------------------------------
Profile
-----------------------------------*/
function setCurrentProfile() {
// REPLACE USER'S INFORMATIONS
$(".js_current_profile_displayname").text(current_display_name);
$(".js_current_profile_username").text(current_acct);
$(".js_current_profile_link").attr("href", current_url);
$(".js_current_header_image").attr("src", current_header);
$(".js_current_profile_image").attr("src", current_avatar);
$(".js_current_toots_count").text(current_statuses_count);
$(".js_current_following_count").text(current_following_count);
$(".js_current_followers_count").text(current_followers_count);
$(".current_toots_count_link").attr("href", current_statuses_count_link);
$(".current_following_count_link").attr("href", current_following_count_link);
$(".current_followers_count_link").attr("href", current_followers_count_link);
replace_emoji();
}
/*----------------------------------
Set User recent images
----------------------------------*/
function putMessage(Message) {
$('#overlay_message').addClass('view');
$('#overlay_message section span').text(Message);
setTimeout(function(){
$("#overlay_message").removeClass("view");
},3000);
};

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -1,73 +0,0 @@
HEAD
-----
1.4.1
-----
- Added support for CommonJS.
- Added support for package managers: Jam (http://jamjs.org), volo (http://volojs.org), Component (http://component.io), jspm (http://jspm.io).
- The expires option now interpretes fractions of numbers (e.g. days) correctly.
1.4.0
-----
- Support for AMD.
- Removed deprecated method `$.cookie('name', null)` for deleting a cookie,
use `$.removeCookie('name')`.
- `$.cookie('name')` now returns `undefined` in case such cookie does not exist
(was `null`). Because the return value is still falsy, testing for existence
of a cookie like `if ( $.cookie('foo') )` keeps working without change.
- Renamed bower package definition (component.json -> bower.json) for usage
with up-to-date bower.
- Badly encoded cookies no longer throw exception upon reading but do return
undefined (similar to how we handle JSON parse errors with json = true).
- Added conversion function as optional last argument for reading,
so that values can be changed to a different representation easily on the fly.
Useful for parsing numbers for instance:
```javascript
$.cookie('foo', '42');
$.cookie('foo', Number); // => 42
```
1.3.1
-----
- Fixed issue where it was no longer possible to check for an arbitrary cookie,
while json is set to true, there was a SyntaxError thrown from JSON.parse.
- Fixed issue where RFC 2068 decoded cookies were not properly read.
1.3.0
-----
- Configuration options: `raw`, `json`. Replaces raw option, becomes config:
```javascript
$.cookie.raw = true; // bypass encoding/decoding the cookie value
$.cookie.json = true; // automatically JSON stringify/parse value
```
Thus the default options now cleanly contain cookie attributes only.
- Removing licensing under GPL Version 2, the plugin is now released under MIT License only
(keeping it simple and following the jQuery library itself here).
- Bugfix: Properly handle RFC 2068 quoted cookie values.
- Added component.json for bower.
- Added jQuery plugin package manifest.
- `$.cookie()` returns all available cookies.
1.2.0
-----
- Adding `$.removeCookie('foo')` for deleting a cookie, using `$.cookie('foo', null)` is now deprecated.
1.1
---
- Adding default options.

View File

@ -1,51 +0,0 @@
##Issues
- Report issues or feature requests on [GitHub Issues](https://github.com/carhartl/jquery-cookie/issues).
- If reporting a bug, please add a [simplified example](http://sscce.org/).
##Pull requests
- Create a new topic branch for every separate change you make.
- Create a test case if you are fixing a bug or implementing an important feature.
- Make sure the build runs successfully.
## Development
###Tools
We use the following tools for development:
- [Qunit](http://qunitjs.com/) for tests.
- [NodeJS](http://nodejs.org/download/) required to run grunt.
- [Grunt](http://gruntjs.com/getting-started) for task management.
###Getting started
Install [NodeJS](http://nodejs.org/).
Install globally grunt-cli using the following command:
$ npm install -g grunt-cli
Browse to the project root directory and install the dev dependencies:
$ npm install -d
To execute the build and tests run the following command in the root of the project:
$ grunt
You should see a green message in the console:
Done, without errors.
###Tests
You can also run the tests in the browser.
Start a test server from the project root:
$ grunt connect:tests
This will automatically open the test suite at http://127.0.0.1:9998 in the default browser, with livereload enabled.
_Note: we recommend cleaning all the browser cookies before running the tests, that can avoid false positive failures._
###Automatic build
You can build automatically after a file change using the following command:
$ grunt watch

View File

@ -1,168 +0,0 @@
/*jshint node:true, quotmark:single */
'use strict';
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
qunit: {
all: 'test/index.html'
},
jshint: {
options: {
jshintrc: true
},
grunt: 'Gruntfile.js',
source: 'src/**/*.js',
tests: 'test/**/*.js'
},
uglify: {
options: {
banner: '/*! <%= pkg.name %> v<%= pkg.version %> | <%= pkg.license %> */\n'
},
build: {
files: {
'build/jquery.cookie-<%= pkg.version %>.min.js': 'src/jquery.cookie.js'
}
}
},
watch: {
options: {
livereload: true
},
files: '{src,test}/**/*.js',
tasks: 'default'
},
compare_size: {
files: [
'build/jquery.cookie-<%= pkg.version %>.min.js',
'src/jquery.cookie.js'
],
options: {
compress: {
gz: function (fileContents) {
return require('gzip-js').zip(fileContents, {}).length;
}
}
}
},
connect: {
saucelabs: {
options: {
port: 9999,
base: ['.', 'test']
}
},
tests: {
options: {
port: 9998,
base: ['.', 'test'],
open: 'http://127.0.0.1:9998',
keepalive: true,
livereload: true
}
}
},
'saucelabs-qunit': {
all: {
options: {
urls: ['http://127.0.0.1:9999'],
build: process.env.TRAVIS_JOB_ID,
browsers: [
// iOS
{
browserName: 'iphone',
platform: 'OS X 10.9',
version: '7.1'
},
{
browserName: 'ipad',
platform: 'OS X 10.9',
version: '7.1'
},
// Android
{
browserName: 'android',
platform: 'Linux',
version: '4.3'
},
// OS X
{
browserName: 'safari',
platform: 'OS X 10.9',
version: '7'
},
{
browserName: 'safari',
platform: 'OS X 10.8',
version: '6'
},
{
browserName: 'firefox',
platform: 'OS X 10.9',
version: '28'
},
// Windows
{
browserName: 'internet explorer',
platform: 'Windows 8.1',
version: '11'
},
{
browserName: 'internet explorer',
platform: 'Windows 8',
version: '10'
},
{
browserName: 'internet explorer',
platform: 'Windows 7',
version: '11'
},
{
browserName: 'internet explorer',
platform: 'Windows 7',
version: '10'
},
{
browserName: 'internet explorer',
platform: 'Windows 7',
version: '9'
},
{
browserName: 'internet explorer',
platform: 'Windows 7',
version: '8'
},
{
browserName: 'firefox',
platform: 'Windows 7',
version: '29'
},
{
browserName: 'chrome',
platform: 'Windows 7',
version: '34'
},
// Linux
{
browserName: 'firefox',
platform: 'Linux',
version: '29'
}
]
}
}
}
});
// Loading dependencies
for (var key in grunt.file.readJSON('package.json').devDependencies) {
if (key !== 'grunt' && key.indexOf('grunt') === 0) {
grunt.loadNpmTasks(key);
}
}
grunt.registerTask('default', ['jshint', 'qunit', 'uglify', 'compare_size']);
grunt.registerTask('saucelabs', ['connect:saucelabs', 'saucelabs-qunit']);
grunt.registerTask('ci', ['jshint', 'qunit', 'saucelabs']);
};

View File

@ -1,162 +0,0 @@
# IMPORTANT!
This project was moved to https://github.com/js-cookie/js-cookie, check [the discussion](https://github.com/carhartl/jquery-cookie/issues/349).
New issues should be opened at https://github.com/js-cookie/js-cookie/issues
# jquery.cookie [![Build Status](https://travis-ci.org/carhartl/jquery-cookie.png?branch=master)](https://travis-ci.org/carhartl/jquery-cookie) [![Code Climate](https://codeclimate.com/github/carhartl/jquery-cookie.png)](https://codeclimate.com/github/carhartl/jquery-cookie)
A simple, lightweight jQuery plugin for reading, writing and deleting cookies.
**If you're viewing this, you're reading the documentation for the old repository.
[View documentation for the latest backwards compatible release (1.5.1).](https://github.com/js-cookie/js-cookie/tree/v1.5.1)**
## Build Status Matrix
[![Selenium Test Status](https://saucelabs.com/browser-matrix/jquery-cookie.svg)](https://saucelabs.com/u/jquery-cookie)
## Installation
Include script *after* the jQuery library (unless you are packaging scripts somehow else):
```html
<script src="/path/to/jquery.cookie.js"></script>
```
**Do not include the script directly from GitHub (http://raw.github.com/...).** The file is being served as text/plain and as such being blocked
in Internet Explorer on Windows 7 for instance (because of the wrong MIME type). Bottom line: GitHub is not a CDN.
The plugin can also be loaded as AMD or CommonJS module.
## Usage
Create session cookie:
```javascript
$.cookie('name', 'value');
```
Create expiring cookie, 7 days from then:
```javascript
$.cookie('name', 'value', { expires: 7 });
```
Create expiring cookie, valid across entire site:
```javascript
$.cookie('name', 'value', { expires: 7, path: '/' });
```
Read cookie:
```javascript
$.cookie('name'); // => "value"
$.cookie('nothing'); // => undefined
```
Read all available cookies:
```javascript
$.cookie(); // => { "name": "value" }
```
Delete cookie:
```javascript
// Returns true when cookie was successfully deleted, otherwise false
$.removeCookie('name'); // => true
$.removeCookie('nothing'); // => false
// Need to use the same attributes (path, domain) as what the cookie was written with
$.cookie('name', 'value', { path: '/' });
// This won't work!
$.removeCookie('name'); // => false
// This will work!
$.removeCookie('name', { path: '/' }); // => true
```
*Note: when deleting a cookie, you must pass the exact same path, domain and secure options that were used to set the cookie, unless you're relying on the default options that is.*
## Configuration
### raw
By default the cookie value is encoded/decoded when writing/reading, using `encodeURIComponent`/`decodeURIComponent`. Bypass this by setting raw to true:
```javascript
$.cookie.raw = true;
```
### json
Turn on automatic storage of JSON objects passed as the cookie value. Assumes `JSON.stringify` and `JSON.parse`:
```javascript
$.cookie.json = true;
```
## Cookie Options
Cookie attributes can be set globally by setting properties of the `$.cookie.defaults` object or individually for each call to `$.cookie()` by passing a plain object to the options argument. Per-call options override the default options.
### expires
expires: 365
Define lifetime of the cookie. Value can be a `Number` which will be interpreted as days from time of creation or a `Date` object. If omitted, the cookie becomes a session cookie.
### path
path: '/'
Define the path where the cookie is valid. *By default the path of the cookie is the path of the page where the cookie was created (standard browser behavior).* If you want to make it available for instance across the entire domain use `path: '/'`. Default: path of page where the cookie was created.
**Note regarding Internet Explorer:**
> Due to an obscure bug in the underlying WinINET InternetGetCookie implementation, IEs document.cookie will not return a cookie if it was set with a path attribute containing a filename.
(From [Internet Explorer Cookie Internals (FAQ)](http://blogs.msdn.com/b/ieinternals/archive/2009/08/20/wininet-ie-cookie-internals-faq.aspx))
This means one cannot set a path using `path: window.location.pathname` in case such pathname contains a filename like so: `/check.html` (or at least, such cookie cannot be read correctly).
### domain
domain: 'example.com'
Define the domain where the cookie is valid. Default: domain of page where the cookie was created.
### secure
secure: true
If true, the cookie transmission requires a secure protocol (https). Default: `false`.
## Converters
Provide a conversion function as optional last argument for reading, in order to change the cookie's value
to a different representation on the fly.
Example for parsing a value into a number:
```javascript
$.cookie('foo', '42');
$.cookie('foo', Number); // => 42
```
Dealing with cookies that have been encoded using `escape` (3rd party cookies):
```javascript
$.cookie.raw = true;
$.cookie('foo', unescape);
```
You can pass an arbitrary conversion function.
## Contributing
Check out the [Contributing Guidelines](CONTRIBUTING.md)
## Authors
[Klaus Hartl](https://github.com/carhartl)

View File

@ -1,18 +0,0 @@
{
"name": "jquery.cookie",
"version": "1.4.1",
"main": [
"src/jquery.cookie.js"
],
"dependencies": {
"jquery": ">=1.2"
},
"ignore": [
"test",
".*",
"*.json",
"*.md",
"*.txt",
"Gruntfile.js"
]
}

View File

@ -1,14 +0,0 @@
{
"name": "jquery.cookie",
"repo": "carhartl/jquery-cookie",
"description": "A simple, lightweight jQuery plugin for reading, writing and deleting cookies",
"version": "1.4.1",
"keywords": [],
"dependencies": {},
"development": {},
"license": "MIT",
"main": "src/jquery.cookie.js",
"scripts": [
"src/jquery.cookie.js"
]
}

View File

@ -1,32 +0,0 @@
{
"name": "cookie",
"version": "1.4.1",
"title": "jQuery Cookie",
"description": "A simple, lightweight jQuery plugin for reading, writing and deleting cookies.",
"author": {
"name": "Klaus Hartl",
"url": "https://github.com/carhartl"
},
"maintainers": [
{
"name": "Klaus Hartl",
"url": "https://github.com/carhartl"
},
{
"name": "Fagner Martins",
"url": "https://github.com/FagnerMartinsBrack"
}
],
"licenses": [
{
"type": "MIT",
"url": "https://raw.github.com/carhartl/jquery-cookie/master/MIT-LICENSE.txt"
}
],
"dependencies": {
"jquery": ">=1.2"
},
"bugs": "https://github.com/carhartl/jquery-cookie/issues",
"homepage": "https://github.com/carhartl/jquery-cookie",
"docs": "https://github.com/carhartl/jquery-cookie#readme"
}

View File

@ -1,50 +0,0 @@
{
"name": "jquery.cookie",
"version": "1.4.1",
"description": "A simple, lightweight jQuery plugin for reading, writing and deleting cookies.",
"main": "src/jquery.cookie.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "grunt"
},
"repository": {
"type": "git",
"url": "git://github.com/carhartl/jquery-cookie.git"
},
"author": "Klaus Hartl",
"license": "MIT",
"gitHead": "bd3c9713222bace68d25fe2128c0f8633cad1269",
"readmeFilename": "README.md",
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-uglify": "~0.2.0",
"grunt-contrib-qunit": "~0.2.0",
"grunt-contrib-watch": "~0.6.1",
"grunt-compare-size": "~0.4.0",
"grunt-saucelabs": "~7.0.0",
"grunt-contrib-connect": "~0.7.1",
"gzip-js": "~0.3.0"
},
"volo": {
"url": "https://raw.github.com/carhartl/jquery-cookie/v{version}/src/jquery.cookie.js"
},
"jspm": {
"main": "jquery.cookie",
"files": ["src/jquery.cookie.js"],
"buildConfig": {
"uglify": true
}
},
"jam": {
"dependencies": {
"jquery": ">=1.2"
},
"main": "src/jquery.cookie.js",
"include": [
"src/jquery.cookie.js"
]
}
}

View File

@ -1,13 +0,0 @@
{
"browser": true,
"camelcase": true,
"jquery": true,
"quotmark": "single",
"globals": {
"define": true,
"module": true,
"require": true
},
"extends": "../.jshintrc"
}

View File

@ -1,114 +0,0 @@
/*!
* jQuery Cookie Plugin v1.4.1
* https://github.com/carhartl/jquery-cookie
*
* Copyright 2006, 2014 Klaus Hartl
* Released under the MIT license
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD (Register as an anonymous module)
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS
module.exports = factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
var pluses = /\+/g;
function encode(s) {
return config.raw ? s : encodeURIComponent(s);
}
function decode(s) {
return config.raw ? s : decodeURIComponent(s);
}
function stringifyCookieValue(value) {
return encode(config.json ? JSON.stringify(value) : String(value));
}
function parseCookieValue(s) {
if (s.indexOf('"') === 0) {
// This is a quoted cookie as according to RFC2068, unescape...
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
}
try {
// Replace server-side written pluses with spaces.
// If we can't decode the cookie, ignore it, it's unusable.
// If we can't parse the cookie, ignore it, it's unusable.
s = decodeURIComponent(s.replace(pluses, ' '));
return config.json ? JSON.parse(s) : s;
} catch(e) {}
}
function read(s, converter) {
var value = config.raw ? s : parseCookieValue(s);
return $.isFunction(converter) ? converter(value) : value;
}
var config = $.cookie = function (key, value, options) {
// Write
if (arguments.length > 1 && !$.isFunction(value)) {
options = $.extend({}, config.defaults, options);
if (typeof options.expires === 'number') {
var days = options.expires, t = options.expires = new Date();
t.setMilliseconds(t.getMilliseconds() + days * 864e+5);
}
return (document.cookie = [
encode(key), '=', stringifyCookieValue(value),
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
options.secure ? '; secure' : ''
].join(''));
}
// Read
var result = key ? undefined : {},
// To prevent the for loop in the first place assign an empty array
// in case there are no cookies at all. Also prevents odd result when
// calling $.cookie().
cookies = document.cookie ? document.cookie.split('; ') : [],
i = 0,
l = cookies.length;
for (; i < l; i++) {
var parts = cookies[i].split('='),
name = decode(parts.shift()),
cookie = parts.join('=');
if (key === name) {
// If second argument (value) is a function it's a converter...
result = read(cookie, value);
break;
}
// Prevent storing a cookie that we couldn't decode.
if (!key && (cookie = read(cookie)) !== undefined) {
result[name] = cookie;
}
}
return result;
};
config.defaults = {};
$.removeCookie = function (key, options) {
// Must not alter options, thus extending a fresh object...
$.cookie(key, '', $.extend({}, options, { expires: -1 }));
return !$.cookie(key);
};
}));

View File

@ -1,9 +0,0 @@
{
"browser": true,
"jquery": true,
"qunit": true,
"-W053": true,
"extends": "../.jshintrc"
}

View File

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jquery.cookie Test Suite</title>
<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.14.0.css">
<script src="http://code.jquery.com/qunit/qunit-1.14.0.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="../src/jquery.cookie.js"></script>
<script src="tests.js"></script>
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
</body>
</html>

View File

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="../src/jquery.cookie.js"></script>
<script>
try {
Object.defineProperty(document, "cookie", { get: function() { return "first=one; ; second=two"; } });
window.testValue = $.cookie("second");
window.ok = true;
} catch (er) {
}
</script>
</head>
<body>
</body>
</html>

View File

@ -1,345 +0,0 @@
// Required for exposing test results to the Sauce Labs API.
// Can be removed when the following issue is fixed:
// https://github.com/axemclion/grunt-saucelabs/issues/84
QUnit.done(function (details) {
window.global_test_results = details;
});
var lifecycle = {
teardown: function () {
$.cookie.defaults = {};
delete $.cookie.raw;
delete $.cookie.json;
$.each($.cookie(), $.removeCookie);
}
};
module('read', lifecycle);
test('simple value', function () {
expect(1);
document.cookie = 'c=v';
strictEqual($.cookie('c'), 'v', 'should return value');
});
test('empty value', function () {
expect(1);
// IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, which
// resulted in a bug while reading such a cookie.
$.cookie('c', '');
strictEqual($.cookie('c'), '', 'should return value');
});
test('not existing', function () {
expect(1);
strictEqual($.cookie('whatever'), undefined, 'return undefined');
});
test('RFC 2068 quoted string', function () {
expect(1);
document.cookie = 'c="v@address.com\\"\\\\\\""';
strictEqual($.cookie('c'), 'v@address.com"\\"', 'should decode RFC 2068 quoted string');
});
test('decode', function () {
expect(1);
document.cookie = encodeURIComponent(' c') + '=' + encodeURIComponent(' v');
strictEqual($.cookie(' c'), ' v', 'should decode key and value');
});
test('decode pluses to space for server side written cookie', function () {
expect(1);
document.cookie = 'c=foo+bar';
strictEqual($.cookie('c'), 'foo bar', 'should convert pluses back to space');
});
test('raw = true', function () {
expect(2);
$.cookie.raw = true;
document.cookie = 'c=%20v';
strictEqual($.cookie('c'), '%20v', 'should not decode value');
// see https://github.com/carhartl/jquery-cookie/issues/50
$.cookie('c', 'foo=bar');
strictEqual($.cookie('c'), 'foo=bar', 'should include the entire value');
});
test('json = true', function () {
expect(1);
if ('JSON' in window) {
$.cookie.json = true;
$.cookie('c', { foo: 'bar' });
deepEqual($.cookie('c'), { foo: 'bar' }, 'should parse JSON');
} else {
ok(true);
}
});
test('not existing with json = true', function () {
expect(1);
if ('JSON' in window) {
$.cookie.json = true;
strictEqual($.cookie('whatever'), undefined, "won't throw exception");
} else {
ok(true);
}
});
test('string with json = true', function () {
expect(1);
if ('JSON' in window) {
$.cookie.json = true;
$.cookie('c', 'v');
strictEqual($.cookie('c'), 'v', 'should return value');
} else {
ok(true);
}
});
test('invalid JSON string with json = true', function () {
expect(1);
if ('JSON' in window) {
$.cookie('c', 'v');
$.cookie.json = true;
strictEqual($.cookie('c'), undefined, "won't throw exception, returns undefined");
} else {
ok(true);
}
});
test('invalid URL encoding', function () {
expect(1);
document.cookie = 'bad=foo%';
strictEqual($.cookie('bad'), undefined, "won't throw exception, returns undefined");
// Delete manually here because it requires raw === true...
$.cookie.raw = true;
$.removeCookie('bad');
});
asyncTest('malformed cookie value in IE (#88, #117)', function () {
expect(1);
// Sandbox in an iframe so that we can poke around with document.cookie.
var iframe = $('<iframe src="malformed_cookie.html"></iframe>')[0];
$(iframe).on('load', function () {
start();
if (iframe.contentWindow.ok) {
strictEqual(iframe.contentWindow.testValue, 'two', 'reads all cookie values, skipping duplicate occurences of "; "');
} else {
// Skip the test where we can't stub document.cookie using
// Object.defineProperty. Seems to work fine in
// Chrome, Firefox and IE 8+.
ok(true, 'N/A');
}
});
document.body.appendChild(iframe);
});
test('Call to read all when there are cookies', function () {
$.cookie('c', 'v');
$.cookie('foo', 'bar');
deepEqual($.cookie(), { c: 'v', foo: 'bar' }, 'returns object containing all cookies');
});
test('Call to read all when there are no cookies at all', function () {
deepEqual($.cookie(), {}, 'returns empty object');
});
test('Call to read all with json: true', function () {
$.cookie.json = true;
$.cookie('c', { foo: 'bar' });
deepEqual($.cookie(), { c: { foo: 'bar' } }, 'returns JSON parsed cookies');
});
test('Call to read all with a badly encoded cookie', function () {
expect(1);
document.cookie = 'bad=foo%';
document.cookie = 'good=foo';
deepEqual($.cookie(), { good: 'foo' }, 'returns object containing all decodable cookies');
// Delete manually here because it requires raw === true...
$.cookie.raw = true;
$.removeCookie('bad');
});
module('write', lifecycle);
test('String primitive', function () {
expect(1);
$.cookie('c', 'v');
strictEqual($.cookie('c'), 'v', 'should write value');
});
test('String object', function () {
expect(1);
$.cookie('c', new String('v'));
strictEqual($.cookie('c'), 'v', 'should write value');
});
test('value "[object Object]"', function () {
expect(1);
$.cookie('c', '[object Object]');
strictEqual($.cookie('c'), '[object Object]', 'should write value');
});
test('number', function () {
expect(1);
$.cookie('c', 1234);
strictEqual($.cookie('c'), '1234', 'should write value');
});
test('null', function () {
expect(1);
$.cookie('c', null);
strictEqual($.cookie('c'), 'null', 'should write value');
});
test('undefined', function () {
expect(1);
$.cookie('c', undefined);
strictEqual($.cookie('c'), 'undefined', 'should write value');
});
test('expires option as days from now', function () {
expect(1);
var sevenDaysFromNow = new Date();
sevenDaysFromNow.setDate(sevenDaysFromNow.getDate() + 21);
strictEqual($.cookie('c', 'v', { expires: 21 }), 'c=v; expires=' + sevenDaysFromNow.toUTCString(),
'should write the cookie string with expires');
});
test('expires option as fraction of a day', function () {
expect(1);
var now = new Date().getTime();
var expires = Date.parse($.cookie('c', 'v', { expires: 0.5 }).replace(/.+expires=/, ''));
// When we were using Date.setDate() fractions have been ignored
// and expires resulted in the current date. Allow 1000 milliseconds
// difference for execution time.
ok(expires > now + 1000, 'should write expires attribute with the correct date');
});
test('expires option as Date instance', function () {
expect(1);
var sevenDaysFromNow = new Date();
sevenDaysFromNow.setDate(sevenDaysFromNow.getDate() + 7);
strictEqual($.cookie('c', 'v', { expires: sevenDaysFromNow }), 'c=v; expires=' + sevenDaysFromNow.toUTCString(),
'should write the cookie string with expires');
});
test('return value', function () {
expect(1);
strictEqual($.cookie('c', 'v'), 'c=v', 'should return written cookie string');
});
test('defaults', function () {
expect(2);
$.cookie.defaults.path = '/foo';
ok($.cookie('c', 'v').match(/path=\/foo/), 'should use options from defaults');
ok($.cookie('c', 'v', { path: '/bar' }).match(/path=\/bar/), 'options argument has precedence');
});
test('raw = true', function () {
expect(1);
$.cookie.raw = true;
strictEqual($.cookie('c[1]', 'v[1]'), 'c[1]=v[1]', 'should not encode');
// Delete manually here because it requires raw === true...
$.removeCookie('c[1]');
});
test('json = true', function () {
expect(1);
$.cookie.json = true;
if ('JSON' in window) {
$.cookie('c', { foo: 'bar' });
strictEqual(document.cookie, 'c=' + encodeURIComponent(JSON.stringify({ foo: 'bar' })), 'should stringify JSON');
} else {
ok(true);
}
});
module('removeCookie', lifecycle);
test('deletion', function () {
expect(1);
$.cookie('c', 'v');
$.removeCookie('c');
strictEqual(document.cookie, '', 'should delete the cookie');
});
test('when sucessfully deleted', function () {
expect(1);
$.cookie('c', 'v');
strictEqual($.removeCookie('c'), true, 'returns true');
});
test('when cookie does not exist', function () {
expect(1);
strictEqual($.removeCookie('c'), true, 'returns true');
});
test('when deletion failed', function () {
expect(1);
$.cookie('c', 'v');
var originalCookie = $.cookie;
$.cookie = function () {
// Stub deletion...
if (arguments.length === 1) {
return originalCookie.apply(null, arguments);
}
};
strictEqual($.removeCookie('c'), false, 'returns false');
$.cookie = originalCookie;
});
test('with options', function () {
expect(1);
var options = { path: '/' };
$.cookie('c', 'v', options);
$.removeCookie('c', options);
strictEqual(document.cookie, '', 'should delete the cookie');
});
test('passing options reference', function () {
expect(1);
var options = { path: '/' };
$.cookie('c', 'v', options);
$.removeCookie('c', options);
deepEqual(options, { path: '/' }, "won't alter options object");
});
test('[] used in name', function () {
expect(1);
$.cookie.raw = true;
document.cookie = 'c[1]=foo';
$.removeCookie('c[1]');
strictEqual(document.cookie, '', 'delete the cookie');
});
module('conversion', lifecycle);
test('read converter', function() {
expect(1);
$.cookie('c', '1');
strictEqual($.cookie('c', Number), 1, 'converts read value');
});
test('read converter with raw = true', function() {
expect(1);
$.cookie.raw = true;
$.cookie('c', '1');
strictEqual($.cookie('c', Number), 1, 'does not decode, but converts read value');
});

Binary file not shown.

View File

@ -1,3 +0,0 @@
Javascript Mastodon API Client Library for Browser Clients
Check out index.html for a "how-to"

View File

@ -1,117 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="mastodon.js"></script>
<script>
// initialize library
// api_user_token has not to be set at this point if you don't have one yet
// NOTE: It needs jQuery!
var api = new MastodonAPI({
instance: "",
api_user_token: ""
});
//
// BASIC REST FUNCTIONS
// you can use every api endpoint from https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md
//
api.post("statuses", {status:"i like pineapple on pizza"}, function (data) {
// will be called if the toot was successful
// data is the http response object
//sidenote: please do not actually execute this request, you could be bullied by your friends
});
api.get("accounts/1/following", [
["since_id", 420],
["max_id", 1337]
], function(data) {
// returns all users account id 1 is following in the id range from 420 to 1337
// you don't have to supply the parameters, you can also just go with .get(endpoint, callback)
});
api.delete("statuses/1", function (data) {
//deletes toot with id 1
});
//
// STREAMING
//
//lets initialize a stream! stream types are
// user for your local home TL and notifications
// public for your federated TL
// public:local for your home TL
// hashtag&tag=fuckdonaldtrump for the stream of #fuckdonaldtrump
api.stream("user", function(data) {
// data is an object containing two entries
// event determines which type of data you got
// payload is the actual data
// event can be notification or update
if (data.event === "notification") {
// data.payload is a notification
} else if (data.event === "update") {
// status update for one of your timelines
} else {
// probably an error
}
})
// AUTH
// first, we register our application
// for this we need no key since we don't have one yet
api.registerApplication("my cool application name",
window.location.href, // redirect uri, we will need this later on
["read", "write", "follow"], //scopes
"http://mycoolwebsite.com", //website on the login screen
function(data) {
// we got our application
// lets save it to our browser storage
localStorage.setItem("mastodon_client_id", data["client_id"]);
localStorage.setItem("mastodon_client_secret", data["client_secret"]);
localStorage.setItem("mastodon_client_redirect_uri", data["redirect_uri"]);
// now, that we have saved our application data, generate an oauth url and send
// our user to it!
window.location.href = api.generateAuthLink(data["client_id"],
data["redirect_uri"],
"code", // oauth method
["read", "write", "follow"] //scopes
);
}
);
// now we get to the part why the redirect uri was set to our current location
// we can just access to code from the url hash
if (window.location.href.indexOf("?code=") !== -1) {
// nice, we got our auth code!
// lets put it into a variable
var authCode = window.location.href.replace(window.location.origin + window.location.pathname + "?code=", "");
// nice variable clusterfuck, eh?
// we have everything needed to access our oauth token
api.getAccessTokenFromAuthCode(
localStorage.getItem("mastodon_client_id"),
localStorage.getItem("mastodon_client_secret"),
localStorage.getItem("mastodon_client_redirect_uri"),
authCode,
function(data) {
// AAAND DATA CONTAINS OUR TOKEN!
// use api.setConfig("api_user_token", tokenvar) to set it without having to reinit the entire
// library.
}
)
}
</script>
</head>
<body>
</body>
</html>

View File

@ -1,277 +0,0 @@
// mastodon javascript lib
// by @kirschn@pleasehug.me 2017
// no fucking copyright
// do whatever you want with it
// but please don't hurt it (and keep this header)
var MastodonAPI = function(config) {
var apiBase = config.instance + "/api/v1/";
return {
setConfig: function (key, value) {
// modify initial config afterwards
config[key] = value;
},
getConfig: function(key) {
//get config key
return config[key];
},
get: function (endpoint) {
// for GET API calls
// can be called with two or three parameters
// endpoint, callback
// or
// endpoint, queryData, callback
// where querydata is an object {["paramname1", "paramvalue1], ["paramname2","paramvalue2"]}
// variables
var queryData, callback,
queryStringAppend = "?";
// check with which arguments we're supplied
if (typeof arguments[1] === "function") {
queryData = {};
callback = arguments[1];
} else {
queryData = arguments[1];
callback = arguments[2];
}
// build queryData Object into a URL Query String
for (var i in queryData) {
if (queryData.hasOwnProperty(i)) {
if (typeof queryData[i] === "string") {
queryStringAppend += queryData[i] + "&";
} else if (typeof queryData[i] === "object") {
queryStringAppend += queryData[i].name + "="+ queryData[i].data + "&";
}
}
}
// ajax function
$.ajax({
url: apiBase + endpoint + queryStringAppend,
type: "GET",
headers: {"Authorization": "Bearer " + config.api_user_token},
success: function(data, textStatus, xhr) {
//weeey it was successful
console.log("Successful GET API request to " +apiBase+endpoint);
responce_headers = xhr.getAllResponseHeaders();
//aaand start the callback
//might have to check what "textStatus" actually is, jquery docs are a bit dodgy
callback(data,textStatus);
},
error: function(xhr, textStatus, errorThrown) {
putMessage(`[${xhr.status}] ${xhr.responseJSON['error']}`);
if ( xhr.status === 401 ) {
location.href = "/logout"
}
}
});
},
getArray: function (endpoint) {
// for GET API calls
// can be called with two or three parameters
// endpoint, callback
// or
// endpoint, queryData, callback
// where querydata is an object {["paramname1", "paramvalue1], ["paramname2","paramvalue2"]}
// variables
var queryData, callback,
queryStringAppend = "?";
// check with which arguments we're supplied
if (typeof arguments[1] === "function") {
queryData = {};
callback = arguments[1];
} else {
queryData = arguments[1];
callback = arguments[2];
}
// build queryData Object into a URL Query String
for (var i in queryData) {
if (queryData.hasOwnProperty(i)) {
if (typeof queryData[i] === "string") {
queryStringAppend += queryData[i] + "&";
} else if (typeof queryData[i] === "object") {
for ( var j in queryData[i].data ){
queryStringAppend += queryData[i].name + "[]="+ queryData[i].data[j] + "&";
}
}
}
}
// ajax function
$.ajax({
url: apiBase + endpoint + queryStringAppend,
type: "GET",
headers: {"Authorization": "Bearer " + config.api_user_token},
success: function(data, textStatus, xhr) {
//weeey it was successful
console.log("Successful GET API request to " +apiBase+endpoint);
responce_headers = xhr.getAllResponseHeaders();
//aaand start the callback
//might have to check what "textStatus" actually is, jquery docs are a bit dodgy
callback(data,textStatus);
},
error: function(xhr, textStatus, errorThrown) {
putMessage(`[${xhr.status}] ${xhr.responseJSON['error']}`);
if ( xhr.status === 401 ) {
location.href = "/logout"
}
}
});
},
getOther: function (domainAndEndpoint) {
var queryData, callback,
queryStringAppend = "?";
// check with which arguments we're supplied
if (typeof arguments[1] === "function") {
queryData = {};
callback = arguments[1];
} else {
queryData = arguments[1];
callback = arguments[2];
}
// build queryData Object into a URL Query String
for (var i in queryData) {
if (queryData.hasOwnProperty(i)) {
if (typeof queryData[i] === "string") {
queryStringAppend += queryData[i] + "&";
} else if (typeof queryData[i] === "object") {
queryStringAppend += queryData[i].name + "="+ queryData[i].data + "&";
}
}
}
// ajax function
$.ajax({
url: domainAndEndpoint + queryStringAppend,
type: "GET",
success: function(data, textStatus, xhr) {
//weeey it was successful
console.log("Successful GET API request to " +domainAndEndpoint);
responce_headers = xhr.getAllResponseHeaders();
//aaand start the callback
//might have to check what "textStatus" actually is, jquery docs are a bit dodgy
callback(data,textStatus);
},
error: function(xhr, textStatus, errorThrown) {
putMessage(`[${xhr.status}] ${xhr.responseJSON['error']}`);
if ( xhr.status === 401 ) {
location.href = "/logout"
}
}
});
},
post: function (endpoint) {
// for POST API calls
var postData, callback;
// check with which arguments we're supplied
if (typeof arguments[1] === "function") {
postData = {};
callback = arguments[1];
} else {
postData = arguments[1];
callback = arguments[2];
}
$.ajax({
url: apiBase + endpoint,
type: "POST",
data: postData,
headers: {"Authorization": "Bearer " + config.api_user_token},
success: function(data, textStatus) {
console.log("Successful POST API request to " +apiBase+endpoint);
callback(data,textStatus)
},
error: function(xhr, textStatus, errorThrown) {
putMessage(`[${xhr.status}] ${xhr.responseJSON['error']}`);
if ( xhr.status === 401 ) {
location.href = "/logout"
}
}
});
},
postMedia: function (endpoint) {
// for POST API calls
var postData, callback;
// check with which arguments we're supplied
if (typeof arguments[1] === "function") {
postData = {};
callback = arguments[1];
} else {
postData = arguments[1];
callback = arguments[2];
}
$.ajax({
url: apiBase + endpoint,
type: "POST",
data: postData,
contentType: false,
processData: false,
headers: {"Authorization": "Bearer " + config.api_user_token},
success: function(data, textStatus) {
console.log("Successful POST API request to " +apiBase+endpoint);
callback(data,textStatus)
},
error: function(xhr, textStatus, errorThrown) {
putMessage(`[${xhr.status}] ${xhr.responseJSON['error']}`);
if ( xhr.status === 401 ) {
location.href = "/logout"
}
}
});
},
delete: function (endpoint, callback) {
// for DELETE API calls.
$.ajax({
url: apiBase + endpoint,
type: "DELETE",
headers: {"Authorization": "Bearer " + config.api_user_token},
success: function(data, textStatus) {
console.log("Successful DELETE API request to " +apiBase+endpoint);
callback(data,textStatus)
},
error: function(xhr, textStatus, errorThrown) {
putMessage(`[${xhr.status}] ${xhr.responseJSON['error']}`);
if ( xhr.status === 401 ) {
location.href = "/logout"
}
}
});
},
stream: function (streamType, onData) {
// Event Stream Support
// websocket streaming is undocumented. i had to reverse engineer the fucking web client.
// streamType is either
// user for your local home TL and notifications
// public for your federated TL
// public:local for your home TL
// hashtag&tag=fuckdonaldtrump for the stream of #fuckdonaldtrump
// callback gets called whenever new data ist recieved
// callback { event: (eventtype), payload: {mastodon object as described in the api docs} }
// eventtype could be notification (=notification) or update (= new toot in TL)
var es = new WebSocket("wss://" + apiBase.substr(8)
+"streaming?access_token=" + config.api_user_token + "&stream=" + streamType);
var listener = function (event) {
console.log("Got Data from Stream " + streamType);
event = JSON.parse(event.data);
event.payload = JSON.parse(event.payload);
onData(event);
};
es.onmessage = listener;
}
};
};
// node.js
if (typeof module !== 'undefined') { module.exports = MastodonAPI; };

File diff suppressed because it is too large Load Diff

View File

@ -1,223 +0,0 @@
/**
* http://www.openjs.com/scripts/events/keyboard_shortcuts/
* Version : 2.01.B
* By Binny V A
* License : BSD
*/
shortcut = {
'all_shortcuts':{},//All the shortcuts are stored in this array
'add': function(shortcut_combination,callback,opt) {
//Provide a set of default options
var default_options = {
'type':'keydown',
'propagate':false,
'disable_in_input':false,
'target':document,
'keycode':false
}
if(!opt) opt = default_options;
else {
for(var dfo in default_options) {
if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
}
}
var ele = opt.target;
if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
var ths = this;
shortcut_combination = shortcut_combination.toLowerCase();
//The function to be called at keypress
var func = function(e) {
e = e || window.event;
if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields
var element;
if(e.target) element=e.target;
else if(e.srcElement) element=e.srcElement;
if(element.nodeType==3) element=element.parentNode;
if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
}
//Find Which key is pressed
if (e.keyCode) code = e.keyCode;
else if (e.which) code = e.which;
var character = String.fromCharCode(code).toLowerCase();
if(code == 188) character=","; //If the user presses , when the type is onkeydown
if(code == 190) character="."; //If the user presses , when the type is onkeydown
var keys = shortcut_combination.split("+");
//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
var kp = 0;
//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
var shift_nums = {
"`":"~",
"1":"!",
"2":"@",
"3":"#",
"4":"$",
"5":"%",
"6":"^",
"7":"&",
"8":"*",
"9":"(",
"0":")",
"-":"_",
"=":"+",
";":":",
"'":"\"",
",":"<",
".":">",
"/":"?",
"\\":"|"
}
//Special Keys - and their codes
var special_keys = {
'esc':27,
'escape':27,
'tab':9,
'space':32,
'return':13,
'enter':13,
'backspace':8,
'scrolllock':145,
'scroll_lock':145,
'scroll':145,
'capslock':20,
'caps_lock':20,
'caps':20,
'numlock':144,
'num_lock':144,
'num':144,
'pause':19,
'break':19,
'insert':45,
'home':36,
'delete':46,
'end':35,
'pageup':33,
'page_up':33,
'pu':33,
'pagedown':34,
'page_down':34,
'pd':34,
'left':37,
'up':38,
'right':39,
'down':40,
'f1':112,
'f2':113,
'f3':114,
'f4':115,
'f5':116,
'f6':117,
'f7':118,
'f8':119,
'f9':120,
'f10':121,
'f11':122,
'f12':123
}
var modifiers = {
shift: { wanted:false, pressed:false},
ctrl : { wanted:false, pressed:false},
alt : { wanted:false, pressed:false},
meta : { wanted:false, pressed:false} //Meta is Mac specific
};
if(e.ctrlKey) modifiers.ctrl.pressed = true;
if(e.shiftKey) modifiers.shift.pressed = true;
if(e.altKey) modifiers.alt.pressed = true;
if(e.metaKey) modifiers.meta.pressed = true;
for(var i=0; k=keys[i],i<keys.length; i++) {
//Modifiers
if(k == 'ctrl' || k == 'control') {
kp++;
modifiers.ctrl.wanted = true;
} else if(k == 'shift') {
kp++;
modifiers.shift.wanted = true;
} else if(k == 'alt') {
kp++;
modifiers.alt.wanted = true;
} else if(k == 'meta') {
kp++;
modifiers.meta.wanted = true;
} else if(k.length > 1) { //If it is a special key
if(special_keys[k] == code) kp++;
} else if(opt['keycode']) {
if(opt['keycode'] == code) kp++;
} else { //The special keys did not match
if(character == k) kp++;
else {
if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
character = shift_nums[character];
if(character == k) kp++;
}
}
}
}
if(kp == keys.length &&
modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
modifiers.shift.pressed == modifiers.shift.wanted &&
modifiers.alt.pressed == modifiers.alt.wanted &&
modifiers.meta.pressed == modifiers.meta.wanted) {
callback(e);
if(!opt['propagate']) { //Stop the event
//e.cancelBubble is supported by IE - this will kill the bubbling process.
e.cancelBubble = true;
e.returnValue = false;
//e.stopPropagation works in Firefox.
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
return false;
}
}
}
this.all_shortcuts[shortcut_combination] = {
'callback':func,
'target':ele,
'event': opt['type']
};
//Attach the function with the event
if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
else ele['on'+opt['type']] = func;
},
//Remove the shortcut - just specify the shortcut and I will remove the binding
'remove':function(shortcut_combination) {
shortcut_combination = shortcut_combination.toLowerCase();
var binding = this.all_shortcuts[shortcut_combination];
delete(this.all_shortcuts[shortcut_combination])
if(!binding) return;
var type = binding['event'];
var ele = binding['target'];
var callback = binding['callback'];
if(ele.detachEvent) ele.detachEvent('on'+type, callback);
else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
else ele['on'+type] = false;
}
}

View File

@ -1,66 +0,0 @@
<?php include ('header.php'); ?>
<!-- MAIN -->
<main id="main" class="federated">
<div class="article_wrap">
<aside class="left_column">
<?php include dirname(__FILE__).('/widgets/side_current_user.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_load_options.php'); ?>
<div class="right_column_clone">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</div>
</aside>
<article class="center_column">
<header class="timeline_header">
<?php include dirname(__FILE__).('/widgets/create_status.php'); ?>
</header>
<div id="js-stream_update">
<button>
View <span></span> new Toots
</button>
</div>
<ul id="js-timeline" class="timeline">
</ul>
<footer id="js-timeline_footer" class="timeline_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
<aside class="right_column">
<section class="side_widgets_wrap">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
</section>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
</div>
</main>
<script>
// namespace
current_file = location.pathname;
setTimeline("timelines/public");
$("#federated_nav").addClass('view');
$('title').text('Halcyon / Federated');
</script>
<?php include ('footer.php'); ?>

View File

@ -1,160 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Halcyon</title>
<link rel="shortcut icon" href="/assets/images/favicon.ico" />
<link rel="stylesheet" type="text/css" href="/assets/css/style.css" media="all" />
<link rel="stylesheet" type="text/css" href="//cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" media="all" />
<script src="//yastatic.net/jquery/3.2.1/jquery.min.js"></script>
<script src="/assets/js/halcyon/halcyonFunctions.js"></script>
<script src="/assets/js/mastodon.js/mastodon.js"></script><!-- thx @kirschn -->
<script src="/assets/js/jquery-cookie/src/jquery.cookie.js"></script>
<script src="/assets/js/shortcut.js"></script>
<script src="/assets/js/replace_emoji.js"></script>
<script src="/assets/js/halcyon/halcyonUI.js"></script>
<script src="//cdn.staticfile.org/twemoji/2.2.5/twemoji.min.js"></script>
<script>
if (
!localStorage.getItem("current_id") |
!localStorage.getItem("current_instance") |
!localStorage.getItem("current_authtoken")
){
location.href = "/login";
} else {
if( $.cookie("session") === "true" ) {
refreshApp();
} else if ( $.cookie("session") === undefined ) {
resetApp();
}
}
</script>
</head>
<body>
<!-- HEADER -->
<header id="header">
<div class="header_nav_wrap">
<!-- HEADER LEFT -->
<nav class="header_left_box">
<ul class="header_nav_list">
<!-- HOME -->
<li id="header_nav_item_home" class="header_nav_item">
<a href="/" id="home_nav">
<i class="fa fa-fw fa-home"></i>
<span>Home</span>
</a>
<div class="home_badge nav_badge invisible"></div>
</li>
<!-- LOCAL -->
<li id="header_nav_item_local" class="header_nav_item local_nav">
<a href="/local" id="local_nav">
<i class="fa fa-fw fa-users"></i>
<span>Local</span>
</a>
<div class="local_badge nav_badge invisible"></div>
</li>
<!-- FEDERATED -->
<li id="header_nav_item_federated" class="header_nav_item federated_nav">
<a href="/federated" id="federated_nav">
<i class="fa fa-fw fa-globe"></i>
<span>Federated</span>
</a>
<div class="federated_badge nav_badge invisible"></div>
</li>
<!-- NOTIFICATIONS -->
<li id="header_nav_item_notifications" class="header_nav_item notifications_nav">
<a href="/notifications" id="notifications_nav">
<i class="fa fa-fw fa-bell"></i>
<span>Notifications</span>
</a>
<div class="notification_badge nav_badge invisible"></div>
</li>
</ul>
</nav>
<!-- HEADER CENTER -->
<div class="header_center_box">
<h1 class="header_nav_item mastodon_logo logo_box">
<a href="/">
<img src="/assets/images/logo_halcyon.png" alt="Halcyon for Mastodon" />
</a>
</h1>
</div>
<!-- HEADER RIGHT -->
<nav class="header_right_box">
<ul class="header_nav_list">
<!-- SEARCH -->
<li class="header_nav_item serch_form_wrap">
<form class="search_form" action="/search" method="GET">
<input id="search_form" class="search_form_input" placeholder="Search Mastodon" type="text" name="q" accesskey="/"/>
<span class="search_form_submit">
<button type="submit">
<i class="fa fa-fw fa-search"></i>
</button>
</span>
</form>
</li>
<!-- ACCOUNT -->
<li class="header_nav_item my_account_wrap">
<button class="header_account_avatar">
<div class="my_account">
<img class="js_current_profile_image" />
</div>
</button>
<nav class="header_my_account_nav invisible">
<ul>
<li>
<a class="js_current_profile_link emoji_poss">
<span class="js_current_profile_displayname display_name"></span>
<span>View profile</span>
</a>
</li>
</ul>
<ul>
<li>
<a class="header_settings_link" href="">Settings</a>
</li>
<li>
<a href="/logout">Log out</a>
</li>
</ul>
</nav>
</li>
<!-- TOOT -->
<li class="header_nav_item toot_button_wrap">
<button id="creat_status" class="toot_button" accesskey="n">
<div class="toot_button_label">
<i class="fa fa-fw fa-pencil-square-o"></i>
<span>Toot</span>
</div>
</button>
</li>
</ul>
</nav>
</div>
</header>

View File

@ -1,62 +0,0 @@
<?php include ('header.php'); ?>
<!-- MAIN -->
<main id="main" class="home">
<div class="article_wrap">
<aside class="left_column">
<?php include dirname(__FILE__).('/widgets/side_current_user.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_load_options.php'); ?>
<div class="right_column_clone">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</div>
</aside>
<article class="center_column">
<header class="timeline_header">
<?php include dirname(__FILE__).('/widgets/create_status.php'); ?>
</header>
<div id="js-stream_update">
<button>
View <span></span> new Toots
</button>
</div>
<ul id="js-timeline" class="timeline">
</ul>
<footer id="js-timeline_footer" class="timeline_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
<aside class="right_column">
<section class="side_widgets_wrap">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
</section>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
</div>
</main>
<script>
// namespace
current_file = location.pathname;
setTimeline("timelines/home");
$("#home_nav").addClass('view');
$('title').text('Halcyon');
</script>
<?php include ('footer.php'); ?>

View File

@ -1,76 +0,0 @@
<?php include ('header.php'); ?>
<!-- MAIN -->
<main id="main">
<div class="article_wrap">
<aside class="left_column">
<?php include dirname(__FILE__).('/widgets/side_current_user.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_load_options.php'); ?>
<div class="right_column_clone">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</div>
</aside>
<article class="center_column">
<header class="timeline_header">
<?php include dirname(__FILE__).('/widgets/create_status.php'); ?>
</header>
<div id="js-stream_update">
<button>
View <span></span> new Toots
</button>
</div>
<ul id="js-timeline" class="timeline">
</ul>
<footer id="js-timeline_footer" class="timeline_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
<aside class="right_column">
<section class="side_widgets_wrap">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
</section>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
</div>
</main>
<script>
// namespace
current_file = location.pathname;
if (
localStorage.getItem("setting_local_instance") === "default" |
localStorage.getItem("setting_local_instance") === current_instance
) {
setTimeline("timelines/public", [{name:"local",data:"ture"}]);
} else {
setOtherTimeline(localStorage.getItem("setting_local_instance")+"/api/v1/", [{name:"local",data:"ture"}]);
}
$("#local_nav").addClass('view');
$('title').text('Halcyon / Local');
</script>
<?php include ('footer.php'); ?>

View File

@ -1,571 +0,0 @@
@charset "utf-8";
/*--------------------------------------
Reset
--------------------------------------*/
* {
margin: 0;
padding: 0;
font-size: 100%;
}
a {
text-decoration: none;
word-break: break-all;
color: inherit;
}
a:hover {
text-decoration: underline;
}
ul, ol {
list-style: none;
padding: 0;
margin: 0;
}
img {
vertical-align: top;
border: 0;
max-width: 100%;
max-height: 100%;
}
button {
font-size: 100%;
}
.clear {
clear: both;
}
.red {
color: red!important;
}
.invisible {
display: none!important;
}
.no-events {
pointer-events: none!important;
}
.no-underline,
.no-underline:hover {
text-decoration: none!important;
}
.disallow_select {
user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
}
.text_ellipsis {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.pointer {
cursor: pointer;
}
.khmer_font {
font-family: "Khmer MN", Helvetica, Arial, sans-serif!important;
}
.gill_font {
font-family: "Gill Sans", Helvetica, Arial, sans-serif!important;
}
.trebuchet_font {
font-family: "Trebuchet MS", Helvetica, Arial, sans-serif!important;
}
h1, h2, h3, h4, h5, h6 {
font-weight: normal;
line-height: 1;
margin: 0;
padding: 0;
}
blockquote, q {
quotes: none;
margin: 0;
}
blockquote * {
margin: 0;
word-break: break-all;
}
blockquote:before, blockquote:after,
q:before, q:after {
content:'';
content:none;
}
article,aside,details,figcaption,figure,
footer,header,hgroup,menu,nav,section {
display:block;
}
textarea {
width: 100%;
}
input {
max-width: 100%;
}
button,
input[type="submit"],
input[type="button"],
input[type="text"],
input[type="password"],
textarea,
select{
background-color: transparent;
border: none;
cursor: pointer;
outline: none;
padding: 0;
appearance: none;
}
input:-webkit-autofill {
-webkit-box-shadow: 0 0 0px 1000px transparent inset;
}
/* Twitter Emoji Prefix */
img.emoji {
height: 1em;
width: 1em;
margin: 0 .05em 0 .1em;
vertical-align: -0.1em;
}
/*--------------------------------------
Base
--------------------------------------*/
html {
font-family : "Trebuchet MS",Helvetica,"ヒラギノ角ゴ Pro W3",
"Hiragino Kaku Gothic Pro",Meiryo,"メイリオ"," Pゴシック",Arial,sans-serif;
font-size : 100%;
line-height : 1;
color: #333;
min-width: 100%;
min-height: 100%;
}
body {
margin: 0;
padding: 0;
min-width: 100%;
min-height: 100%;
word-wrap:break-word;
background-color: #F5F8FA;
}
/*-------------------------------------
HEADER AREA
-------------------------------------*/
#header {
width: 100%;
height: 56px;
color: #fff;
background-color: #222;
box-shadow: 0px 3px 5px rgba(0,0,0,0.26);
position: fixed;
z-index: 999;
}
#header #header_wrap {
display: flex;
justify-content: flex-start;
align-items: center;
width: 100%;
height: 100%;
}
#header #header_wrap > .header_box {
height: 100%;
flex-grow: 1;
flex-shrink: 0;
}
/*-------------------------------------
HEADER AREA: TITLE
-------------------------------------*/
#header #header_wrap .header_box.header_right_box {
display: flex;
justify-content: flex-start;
}
#header #header_wrap .header_box.header_right_box .title_box {
height: 100%;
margin-left: 24px;
box-sizing: border-box;
}
/*-------------------------------------
HEADER AREA: NAV
-------------------------------------*/
#header #header_wrap .header_box.header_left_box {
display: flex;
justify-content: flex-end;
}
#header #header_wrap .header_box.header_left_box nav {
height: 100%;
}
#header #header_wrap .header_box.header_left_box .nav_box ul {
display: block;
height: 100%;
width: 100%;
}
#header #header_wrap .header_box.header_left_box .nav_box ul a {
height: 100%;
}
#header #header_wrap .header_box.header_left_box .nav_box ul li {
display: block;
float: left;
cursor: pointer;
height: calc(100% - 5px*2 );
margin-top: 5px;
border-bottom: 0px solid #007BD0;
}
#header #header_wrap .header_box.header_left_box .nav_box ul li span {
display: block;
height: 100%;
margin: auto;
padding: 15px 24px;
font-size: 14px;
box-sizing: border-box;
}
#header #header_wrap .header_box.header_left_box .nav_box ul li span i {
margin-right: 4px;
}
#header #header_wrap .header_box.header_left_box .nav_box ul li:hover {
color: #189EFC;
border-bottom-width: 5px;
transition: 0.15s ease-out;
}
/*-------------------------------------
MAIN
-------------------------------------*/
#main {
padding-top: 56px;
}
/*-------------------------------------
FORM
-------------------------------------*/
#main #login_form_wrap {
width: 100%;
height: 560px;
padding: 56px 0;
margin-bottom: -200px;
box-sizing: border-box;
background-image: url("/login/assets/images/background.jpg");
background-size: cover;
background-repeat: no-repeat;
}
#main #login_form_wrap .login_form {
position: relative;
width: 640px;
height: 220px;
padding: 36px 24px;
margin: auto;
overflow: hidden;
background: inherit;
box-sizing: border-box;
border-radius: 4px;
border: 1px solid #C9EFF8;
text-align: center;
box-shadow: 0px 5px 5px rgba(0,0,0,0.26);
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form.expand {
width: 780px;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form::before {
display: block;
position: absolute;
content: "";
top: -3px;
left: -3px;
right: -3px;
bottom: -3px;
background: inherit;
background-position: top center;
filter: blur(3px);
border-radius: 5px;
z-index: 0;
}
#main #login_form_wrap .login_form form {
position: relative;
margin: auto;
z-index: 1;
color: #C9EFF8;
}
#main #login_form_wrap .login_form form a {
color: #fff;
}
#main #login_form_wrap .login_form h2 {
font-size: 32px;
font-weight: 600;
margin-bottom: 16px;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form.expand h2 {
font-size: 42px;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form p {
margin-bottom: 16px;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form.expand p {
opacity: 0;
margin-bottom: 0;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form .login_form_main {
display: flex;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
margin: auto;
height: 32px;
width: 276px;
border: 1px solid #C9EFF8;
border-radius: 32px;
background-color: rgba(0,0,0,.3);
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form.expand .login_form_main {
width: 360px;
height: 42px;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form .login_form_main.active {
box-shadow: 0px 3px 5px rgba(0,0,0,0.26);
}
#main #login_form_wrap .login_form .login_form_main input[name="acct"] {
display: block;
-webkit-appearance : none;
flex-grow: 1;
padding: 4px 0 4px 14px;
color: #C9EFF8;
border: none;
background: none;
box-sizing: border-box;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form.expand .login_form_main input[name="acct"] {
flex-grow: 2;
padding: 8px 0 8px 14px;
transition: 0.25s ease-out;
}
#main #login_form_wrap .login_form .login_form_main .login_form_continue {
display: block;
flex-grow: 1;
color: #C9EFF8;
}
#main #login_form_wrap .login_form .login_form_main .login_form_continue:hover {
color: #fff;
}
#main #login_form_wrap .login_form .login_form_agree {
margin: 16px auto 0;
}
#main #login_form_wrap .login_form .login_form_agree i {
color: #fff;
}
/*-------------------------------------
ARTICLE
-------------------------------------*/
#article {
position: relative;
width: 640px;
margin: auto;
margin-bottom: 56px;
padding: 24px 36px 36px;
border-radius: 4px;
background-color: #fff;
box-sizing: border-box;
box-shadow: 3px 3px 5px rgba(0,0,0,0.26);
}
#article h2 {
font-size: 32px;
font-weight: 600;
margin: 16px 0;
}
#article p {
display: inline-block;
margin-bottom: 16px;
font-size: 16px;
line-height: 1.2;
}
#article .image_wrap {
display: block;
position: relative;
margin: 0 -36px 24px;
border-top: 0.5px solid #555;
border-bottom: 0.5px solid #555;
}
#article .image_wrap ul {
display: block;
position: relative;
width: 100%;
height: 370px;
overflow: hidden;
}
#article .image_wrap ul li {
position: absolute;
top: 0;
left: 0;
}
@keyframes fadeout {
0% {opacity: 1;}
100% {opacity: 0;}
}
@keyframes fadein {
0% {opacity: 0;}
100% {opacity: 1;}
}
#article .image_wrap ul li.fadeout {
animation-name: fadeout;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
#article .image_wrap ul li.fadein {
animation-name: fadein;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
#article .image_wrap .switch_button {
display: block;
opacity: 0;
position: absolute;
top: 0;
width: 30px;
height: 100%;
color: #fff;
background-color: rgba(0, 0, 0, .3);
transition: 0.15s ease-out;
}
#article .image_wrap:hover .switch_button {
opacity: 1;
transition: 0.15s ease-out;
}
@keyframes switching_image_list {
0% {background-color: rgba(0, 0, 0, .3);}
50% {background-color: rgba(0, 0, 0, .8);}
100% {background-color: rgba(0, 0, 0, .3);}
}
#article .image_wrap:hover .switch_button.active {
animation-name: switching_image_list;
animation-duration: 0.35s;
}
#article .image_wrap .switch_button.prev_button {
left: 0;
}
#article .image_wrap .switch_button.next_button {
right: 0;
}
#article a {
color: #189EFC;
}
/*-------------------------------------
FOOTER
-------------------------------------*/
#footer {
width: 640px;
padding: 24px 36px 12px;
box-sizing: border-box;
margin: auto;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
box-shadow: 3px 3px 5px rgba(0,0,0,0.26);
background-color: #222;
}
#footer .footer_anchor {
display: flex;
justify-content: center;
align-items: center;
color: #444;
font-size: 36px;
transition: 0.15s ease-out;
}
#footer .footer_anchor:hover {
color: #555;
transition: 0.15s ease-out;
}
#footer span {
font-size: 14px;
color: #ddd;
margin: auto;
display: block;
text-align: center;
}

View File

@ -1,55 +0,0 @@
$(function() {
$(document).on('change','.login_form_agree #agree', function(e) {
const icon = $(this).parent().find('i.fa');
if ( $(this).prop('checked') ) {
icon.addClass("fa-check-square-o");
icon.removeClass("fa-square-o");
} else if ( !$(this).prop('checked') ) {
icon.addClass("fa-square-o");
icon.removeClass("fa-check-square-o");
}
});
$(document).on('focus', '#main #login_form_wrap .login_form .login_form_main input[name="acct"]', function(e) {
$(this).parent().addClass('active')
$(".login_form").addClass('expand');
})
$(document).on('blur', '#main #login_form_wrap .login_form .login_form_main input[name="acct"]', function(e) {
$(this).parent().removeClass('active')
$(".login_form").removeClass('expand');
})
$(document).on('mousedown', '.image_wrap .switch_button', function(e) {
const self = $(this);
self.addClass('active');
setTimeout(function() {
self.removeClass('active');
}, 500);
})
$(document).on('click', '.image_wrap .prev_button', function(e) {
const firstChild = $(this).parent(".image_wrap").find('ul li:first-child');
firstChild.appendTo(".image_wrap ul");
firstChild.addClass('fadein');
setTimeout(function() {
firstChild.removeClass('fadein');
}, 500);
})
$(document).on('click', '.image_wrap .next_button', function(e) {
const lastChild = $(this).parent(".image_wrap").find('ul li:last-child');;
lastChild.addClass('fadeout');
setTimeout(function() {
lastChild.prependTo(".image_wrap ul");
lastChild.removeClass('fadeout');
}, 500);
})
})

View File

@ -1,70 +0,0 @@
<!DOCTYPE HTML>
<html lang='en'>
<head>
<script>
if(
localStorage.getItem('current_id') |
localStorage.getItem('current_instance') |
localStorage.getItem('current_authtoken')
){
location.href = '/logout';
};
</script>
<?php
#!/usr/bin/env php
#ini_set("display_errors", On);
#error_reporting(E_ALL);
require_once('../../authorize/Mastodon.php');
use HalcyonSuite\HalcyonForMastodon\Mastodon;
use Exception;
$api = new Mastodon();
if ($_GET['code']) {
$domain = htmlspecialchars((string)filter_input(INPUT_GET, 'host'), ENT_QUOTES);
$URL = 'https://'.$domain;
$api->selectInstance($URL);
$response = $api->get_access_token($api->clientWebsite.'/auth?&host='.$domain, htmlspecialchars((string)filter_input(INPUT_GET, 'code'), ENT_QUOTES));
if ($response['html']["access_token"]) {
$access_token = $response['html']["access_token"];
$account_id = $api->accounts_verify_credentials()['html']['id'];
echo "
<script>
localStorage.setItem('current_id', '$account_id');
localStorage.setItem('current_instance', '$domain');
localStorage.setItem('current_authtoken', '$access_token');
localStorage.setItem('setting_post_stream', 'manual');
localStorage.setItem('setting_post_privacy', 'public');
localStorage.setItem('setting_local_instance', 'default');
localStorage.setItem('setting_search_filter', 'all');
localStorage.setItem('what_to_follow_0', JSON.stringify({id:'',username:'Halcyon',display_name:'Halcyon for Mastodon',url:'https://mastodon.social/@Halcyon',avatar:'https://files.mastodon.social/accounts/avatars/000/132/199/original/1ca33302b092376b.png'}));
localStorage.setItem('what_to_follow_1', JSON.stringify({id:'',username:'Gargron',display_name:'Eugen',url:'https://mastodon.social/@Gargron',avatar:'https://files.mastodon.social/accounts/avatars/000/000/001/original/J3IHut1v.png'}));
localStorage.setItem('what_to_follow_2', JSON.stringify({id:'',username:'Mastodon',display_name:'Mastodon',url:'https://mastodon.social/@Mastodon',avatar:'https://files.mastodon.social/accounts/avatars/000/013/179/original/logo-41b041930be24e8039129c8ac4ff4840ef467f40c3f2d5044db50a4b15ceb285.png'}));
location.href = '/';
</script>
";
}
}
?>
<script src="//yastatic.net/jquery/3.2.1/jquery.min.js"></script>
<script src="/assets/js/mastodon.js/mastodon.js"></script>
</head>
<body>
</body>
</html>

View File

@ -1,234 +0,0 @@
<?php
#!/usr/bin/env php
#ini_set("display_errors", On);
#error_reporting(E_ALL);
require_once('../../authorize/Mastodon.php');
use HalcyonSuite\HalcyonForMastodon\Mastodon;
use Exception;
?>
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Halcyon for Mastodon</title>
<link rel="shortcut icon" href="/assets/images/favicon.ico" />
<link rel="stylesheet" type="text/css" href="/login/assets/css/style.css" media="all" />
<link rel="stylesheet" type="text/css" href="//cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" media="all" />
<script src="//yastatic.net/jquery/3.2.1/jquery.min.js"></script>
<script src="/assets/js/jquery-cookie/src/jquery.cookie.js"></script>
<script src="/login/assets/js/halcyon_login.js"></script>
<script>
if(
localStorage.getItem("current_id") |
localStorage.getItem("current_instance") |
localStorage.getItem("current_authtoken")
){
location.href = "/";
};
</script>
<?php
if (isset($_POST['acct'])) {
$domain = explode("@", mb_strtolower(htmlspecialchars((string)filter_input(INPUT_POST, 'acct'), ENT_QUOTES)))[2];
$URL = 'https://'.$domain;
$api = new Mastodon();
if ( !preg_match('/(^[a-z0-9\-\.\/]+?\.[a-z0-9-]+$)/', $domain) ) {
header('Location: '.$api->clientWebsite.'/login?cause=domain', true, 303);
die();
} else {
try {
$client_id = $api->getInstance($URL)["client_id"];
$authorizeURL = $URL.'/oauth/authorize?client_id='.$client_id.'&response_type=code&scope=read+write+follow&website='.$api->clientWebsite.'&redirect_uri='.urlencode($api->clientWebsite.'/auth?&host='.$domain);
header("Location: {$authorizeURL}", true, 303);
die();
} catch (Exception $e) {
header('Location: '.$api->clientWebsite.'/login?cause=domain', true, 303);
die();
}
}
}
?>
</head>
<body>
<!-- HEADER -->
<header id="header">
<div id="header_wrap">
<div id="header_title_wrap" class="header_box header_right_box">
<div class="header_box_child title_box">
<a href="/">
<!-- TITLE IMAGE -->
<img src="/login/assets/images/halcyon-title.png" alt="Halcyon for mastodon"/>
</a>
</div>
</div>
<div id="header_menu_wrap" class="header_box header_left_box">
<nav class="header_box_child nav_box">
<ul>
<!-- NEWS-->
<!--<a href="https://mastodon.social/@halcyon" class="no-underline">
<li>
<span><i class="fa fa-newspaper-o" aria-hidden="true"></i>News</span>
</li>
</a>-->
<!-- SOURCE-->
<a href="https://github.com/halcyon-suite/halcyon" class="no-underline">
<li>
<span><i class="fa fa-code" aria-hidden="true"></i>Source</span>
</li>
</a>
<!-- TERMS -->
<a class="no-underline">
<li>
<span><i class="fa fa-balance-scale" aria-hidden="true"></i>Terms</span>
</li>
</a>
<!-- CONTACT -->
<a href="http://www.nikisoft.one/contact.php" class="no-underline">
<li>
<span><i class="fa fa-envelope" aria-hidden="true"></i>Contact</span>
</li>
</a>
<!-- SIGN IN -->
<a href="#login_form_wrap" class="no-underline">
<li>
<span><i class="fa fa-user-circle-o" aria-hidden="true"></i>Login</span>
</li>
</a>
</ul>
</nav>
</div>
</div>
</header>
<!-- MAIN -->
<main id="main">
<div id="login_form_wrap">
<div class="login_form">
<form method="POST" >
<h2>Login to Halcyon</h2>
<p>
or <a href="https://joinmastodon.org/">create an account</a>
</p>
<div class="session_aleart">
<span></span>
</div>
<div class="login_form_main">
<input name="acct" type="text" class="login_form_input" placeholder="@halcyon@mastodon.social" required/>
<label class="login_form_continue pointer">
<i class="fa fa-chevron-circle-right" aria-hidden="true"></i>
<input id="login_continue" type="submit" value="" class="invisible"></input>
</label>
</div>
<div class="login_form_agree">
<label class="login_form_agree_check disallow_select pointer">
<i class="fa fa-check-square-o" aria-hidden="true"></i>
I agree with the <a href="/terms">Terms</a>
<input id="agree" type="checkbox" required checked class="invisible"/>
</label>
</div>
</form>
</div>
</div>
<article id="article">
<h2>What is Halcyon</h2>
<p>
Halcyon is standard <span style="font-weight: bold">Twitter like client</span> of Mastodon, And you can use it just by login to your instance. Let's Toot like a tweet.
</p>
<div class="image_wrap">
<ul>
<li><img src="/login/assets/images/preview2.png" alt="halcyon_screenshot"/></li>
<li><img src="/login/assets/images/preview1.png" alt="halcyon_screenshot"/></li>
<li><img src="/login/assets/images/preview0.png" alt="halcyon_screenshot"/></li>
</ul>
<button class="prev_button switch_button"><i class="fa fa-angle-left" aria-hidden="true"></i></button>
<button class="next_button switch_button"><i class="fa fa-angle-right" aria-hidden="true"></i></button>
</div>
<h2>Contact / Feedback</h2>
<p>
Mastodon: <a href="http://social.wiuwiu.de/@nipos" target="_blank">nipos@social.wiuwiu.de</a><br />
Email: <a href="http://www.nikisoft.one/contact.php" target="_blank">Use my contact form</a><br />
Github: <a href="https://github.com/halcyon-suite" target="_blank">/halcyon-suite</a>
</p>
<h2>Help us</h2>
<p>
Bitcoin: 1D6GThQqHQYnruKYrKyW9JC86ZGWxjt1hK<br />
</p>
</article>
</main>
<!-- FOOTER -->
<footer id="footer">
<div class="footer_anchor">
<a href="#">
<i class="fa fa-angle-up" aria-hidden="true"></i>
</a>
</div>
<span>Photo by <a href="https://www.flickr.com/photos/95387826@N08/">Michio Morimoto on Flickr</a> (CC BY 2.0)</span>
</footer>
</body>
<?php if (isset($_GET['cause'])): ?>
<script>
$(function() {
var cause = "<?= htmlspecialchars((string)filter_input(INPUT_GET, 'cause'), ENT_QUOTES) ?>";
if ( cause === "domain" ) {
$('.login_form_main').addClass('error');
$('.session_aleart').removeClass('invisible');
$('.session_aleart > span').text('This instance does not exsist.');
}
});
$(document).on('click','.login_form_main', function(e) {
$(this).removeClass('error');
});
</script>
<?php endif; ?>
</html>

View File

@ -1,128 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Halcyon for Mastodon</title>
<link rel="shortcut icon" href="/assets/images/favicon.ico" />
<link rel="stylesheet" type="text/css" href="/login/assets/css/style.css" media="all" />
<link rel="stylesheet" type="text/css" href="//cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" media="all" />
<script src="//yastatic.net/jquery/3.2.1/jquery.min.js"></script>
<script src="/assets/js/jquery-cookie/src/jquery.cookie.js"></script>
<script src="/login/assets/js/halcyon_login.js"></script>
</head>
<body>
<header id="header">
<div id="header_wrap">
<div id="header_title_wrap" class="header_box header_right_box">
<div class="header_box_child title_box">
<a href="/">
<!-- TITLE IMAGE -->
<img src="/login/assets/images/halcyon-title.png" alt="Halcyon for mastodon"/>
</a>
</div>
</div>
<div id="header_menu_wrap" class="header_box header_left_box">
<nav class="header_box_child nav_box">
<ul>
<!-- NEWS-->
<!--<a href="https://mastodon.social/@halcyon" class="no-underline">
<li>
<span><i class="fa fa-newspaper-o" aria-hidden="true"></i>News</span>
</li>
</a>-->
<!-- SOURCE-->
<a href="https://github.com/halcyon-suite/halcyon" class="no-underline">
<li>
<span><i class="fa fa-code" aria-hidden="true"></i>Source</span>
</li>
</a>
<!-- TERMS -->
<a class="no-underline">
<li>
<span><i class="fa fa-balance-scale" aria-hidden="true"></i>Terms</span>
</li>
</a>
<!-- CONTACT -->
<a href="http://www.nikisoft.one/contact.php" class="no-underline">
<li>
<span><i class="fa fa-envelope" aria-hidden="true"></i>Contact</span>
</li>
</a>
<!-- SIGN IN -->
<a href="#login_form_wrap" class="no-underline">
<li>
<span><i class="fa fa-user-circle-o" aria-hidden="true"></i>Login</span>
</li>
</a>
</ul>
</nav>
</div>
</div>
</header>
<main id="main">
<article id="article">
<h1>Halcyon Terms of Use</h1>
<p class="description">This terms of use agreement is for the users of web service Halcyon for Mastodon (Halcyon for short) hosted at <a href="https://halcyon.social">halcyon.social</a>.</p>
<br/>
<h2>1. Agreement</h2>
<p>By logging into Halcyon you agree to this terms of use agreement. Do not use this service if you do not agree to these terms.</p>
<br/>
<h2>2. Change</h2>
<p>We reserve the right to modify these terms of use at any time if deemed necessary.</p>
<br/>
<h2>3. Account</h2>
<p>Users can connect to various Mastodon accounts from Halcyon, and Halcyon will not interfere with those connection.</p>
<br/>
<h2>4. Content</h2>
<p>Halcyon does not own the right to or hold responsibility for any text, image, animation, audio content accessible from Halcyon. The right and responsibility belong to the owners of instances that host those content.</p>
<br/>
<h2>5. Guideline</h2>
<p>Halcyon reserves the right to terminate service for</p>
<ul>
<li>actions violating the laws of countries</li>
<li>actions contrary to public order and standards of decency</li>
<li>violation of third partys right to intellectual property, brand, privacy, etc.</li>
<li>acts of violence, sexual nature, of discrimination</li>
<li>phishing or spamming</li>
<li>actions causing problem to the network infrastructure of Halcyon</li>
</ul>
<br/>
<h2>6. Disclaimer</h2>
<p>Halcyon is not responsible for any damage caused by using this service.</p>
<br/>
<p>Last updated 2017/5/12</p>
</article>
</main>
<footer id="footer">
<div class="footer_anchor">
<a href="#">
<i class="fa fa-angle-up" aria-hidden="true"></i>
</a>
</div>
<span>Photo by <a href="https://www.flickr.com/photos/95387826@N08/">Michio Morimoto on Flickr</a> (CC BY 2.0)</span>
</footer>
</body>

View File

@ -1,69 +0,0 @@
<?php include ('header.php'); ?>
<!-- MAIN -->
<main id="main">
<div class="article_wrap">
<aside class="left_column">
</aside>
<article class="center_column">
<header class="timeline_header">
<ul class="header_items">
<li class="item toots view">
<a href="#">
All
</a>
</li>
</ul>
</header>
<div id="js-stream_update">
<button>
View <span></span> new notiotification
</button>
</div>
<ul id="js-timeline" class="timeline">
</ul>
<footer id="js-timeline_footer" class="timeline_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
<aside class="right_column">
<section class="side_widgets_wrap">
<?php include dirname(__FILE__).('/widgets/side_what_to_follow.php'); ?>
</section>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
</div>
</main>
<script>
// namespace
current_file = location.pathname;
$("#notifications_nav").addClass('view');
// reset count
localStorage.setItem("notification_count", 0);
setNotifications();
$('title').text('Halcyon / Notifications')
</script>
<?php include ('footer.php'); ?>

View File

@ -1,80 +0,0 @@
<?php include ('header.php'); ?>
<!-- MAIN -->
<main id="main">
<?php include dirname(__FILE__).('/widgets/search_header.php'); ?>
<div class="article_wrap">
<aside class="left_column">
<?php include dirname(__FILE__).('/widgets/side_load_options.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
<article class="center_column">
<header class="timeline_header">
<ul class="header_items">
<li class="item toots view">
</li>
</ul>
</header>
<div id="js-stream_update">
<button>
View <span></span> new Toots
</button>
</div>
<ul id="js-timeline" class="timeline">
</ul>
<footer id="js-timeline_footer" class="timeline_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
<aside class="right_column"></aside>
</div>
</main>
<script>
// namespace
current_file = location.pathname;
<?php if (isset($_GET['q'])): ?>
$(function() {
// find by mid
const query = "<?= htmlspecialchars((string)filter_input(INPUT_GET, 'q'), ENT_QUOTES) ?>";
$('#main > .article_wrap > .center_column > .timeline_header > .header_items > .item').text("#"+query);
$('#js-search_title_box > h1').text(query);
$('title').text('#'+query+' - Halcyon Search');
$('#js-search_nav_toots').toggleClass('view');
$('#js-search_nav_toots a ').attr('href','/search'+location.search);
$('#js-search_nav_peoples a ').attr('href','/search/users'+location.search)
if ( localStorage.getItem("setting_search_filter") === "all" ) {
setTimeline("timelines/tag/"+query);
} else if ( localStorage.getItem("setting_search_filter") === "local" ) {
setTimeline("timelines/tag/"+query, [{name:"local",data:"ture"}]);
}
replace_emoji();
});
<?php endif; ?>
</script>
<?php include ('footer.php'); ?>

View File

@ -1,51 +0,0 @@
<?php include ('header.php'); ?>
<!-- MAIN -->
<main id="main">
<?php include dirname(__FILE__).('/widgets/search_header.php'); ?>
<div class="article_wrap">
<aside class="left_column">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
<article class="center_column">
<div id="js-follows_profile">
</div>
<footer id="js-follows_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
</div>
</main>
<script>
// namespace
current_file = location.pathname;
<?php if(isset($_GET['q'])): ?>
const query = "<?= htmlspecialchars((string)filter_input(INPUT_GET, 'q'), ENT_QUOTES) ?>";
$('title').text(query+' - Halcyon Search');
$('#js-search_title_box > h1').text(query);
$('#js-search_nav_peoples').toggleClass('view');
$('#js-search_nav_toots a ').attr('href','/search'+location.search);
$('#js-search_nav_peoples a ').attr('href','/search/users'+location.search);
setUserSearch(query);
<?php endif; ?>
</script>
<?php include ('footer.php'); ?>

View File

@ -1,158 +0,0 @@
<?php include ('header.php'); ?>
<!-- MAIN -->
<main id="main">
<?php include dirname(__FILE__).('/widgets/user_header.php'); ?>
<div class="article_wrap">
<aside class="left_column">
<!-- Profile avatar -->
<div class="profile_icon_box">
<img id="js_profile_image" src="/assets/images/missing.png" mediaaccess="true"/>
</div>
<!-- Display/username, bio-->
<section class="profile_section_wrap">
<h1 class="profile_displayname">
<a id="js_profile_displayname" class="emoji_poss" href="#"></a>
</h1>
<h2 class="profile_username">
@<a id="js_profile_username" href="#"></a><span class="profile_followed_by invisible">FOLLOWS YOU</span>
</h2>
<p id="js_profile_bio" class="profile_bio emoji_poss"></p>
<?php include dirname(__FILE__).('/widgets/user_recent_images.php'); ?>
</section>
<div class="right_column_clone">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</div>
</aside>
<article class="center_column">
<!-- TIMELINE HEADER -->
<header class="timeline_header">
<ul class="header_items">
<!-- TOOT -->
<li class="item toots view">
<a id="toots_link">
Toots
</a>
</li>
<!--- TOOTS & REPLIES -->
<li class="item wreplies">
<a id="with_replies_link">
Toots &amp; replies
</a>
</li>
<!-- MEDIA -->
<li class="item media">
<a id="media_link">
Media
</a>
</li>
</ul>
</header>
<!-- UPDATE BUTTON -->
<div id="js-stream_update">
<button>
View <span></span> new Toots
</button>
</div>
<!-- TIMELINE -->
<ul id="js-timeline" class="timeline">
</ul>
<!-- TIMELINE FOOTER -->
<footer id="js-timeline_footer" class="timeline_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
<aside class="right_column">
<section class="side_widgets_wrap">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
</section>
<!-- FOOTER -->
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
</div>
</main>
<script>
// namespace
current_file = "/user";
$("#toots_link").attr('href', location.pathname+location.search);
$("#with_replies_link").attr('href', location.pathname+'/with_replies'+location.search);
$("#media_link").attr('href', location.pathname+'/media'+location.search);
$("#js-profile_nav_toots").toggleClass("view");
$("#js-profile_nav_toots > a").attr('href', location.pathname+location.search);
$("#js-profile_nav_following > a").attr('href', location.pathname+'/following'+location.search);
$("#js-profile_nav_followers > a").attr('href', location.pathname+'/followers'+location.search);
$("#js-profile_nav_favourites > a").attr('href', location.pathname+'/favourites'+location.search);
<?php if (isset($_GET['mid'])): ?>
$(function() {
// find by mid
const account_id = <?= htmlspecialchars((string)filter_input(INPUT_GET, 'mid'), ENT_QUOTES) ?>;
api.get('accounts/'+account_id, function(userprofile) {
if ( userprofile !== null ) {
$('title').text(replaced_emoji_return(userprofile.display_name)+' (@'+userprofile.acct+') | Halcyon');
setAccount(userprofile);
setTimeline("accounts/"+userprofile.id+"/statuses",[{name:'exclude_replies',data:'true'}]);
setRecentImages(userprofile.id)
} else {
location.href = "/404.php";
}
});
});
<?php elseif((isset($_GET['user']))): ?>
$(function(){
// find by url
<?php
$name = preg_split("/@/", $_GET['user'])[1];
$domain = preg_split("/@/", $_GET['user'])[2];
$url = "https://$domain/@$name";
?>
const query = '<?= htmlspecialchars((string)filter_input(INPUT_GET, 'user'), ENT_QUOTES) ?>';
api.get('search', [{name:'q',data:query},{name:'resolve',data:'true'}], function(search) {
if ( !search.accounts.length ) {
location.href = "/404.php";
} else if ( "@"+search.accounts[0].acct === query ) {
$('title').text(replaced_emoji_return(search.accounts[0].display_name)+' (@'+search.accounts[0].acct+') | Halcyon');
setAccount(search.accounts[0]);
setTimeline("accounts/"+search.accounts[0].id+"/statuses",[{name:'exclude_replies',data:'true'}]);
setRecentImages(search.accounts[0].id)
} else {
location.href = "/404.php";
}
});
})
<?php endif; ?>
</script>
<?php include ('footer.php'); ?>

View File

@ -1,147 +0,0 @@
<?php include ('header.php'); ?>
<!-- MAIN -->
<main id="main">
<?php include dirname(__FILE__).('/widgets/user_header.php'); ?>
<div class="article_wrap">
<aside class="left_column">
<div class="profile_icon_box">
<img id="js_profile_image" src="/assets/images/missing.png" mediaaccess="true"/>
</div>
<section class="profile_section_wrap">
<h1 class="profile_displayname">
<a id="js_profile_displayname" class="emoji_poss" href="#"></a>
</h1>
<h2 class="profile_username">
@<a id="js_profile_username" href="#"></a>
</h2>
<p id="js_profile_bio" class="profile_bio emoji_poss"></p>
<?php include dirname(__FILE__).('/widgets/user_recent_images.php'); ?>
</section>
<div class="right_column_clone">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</div>
</aside>
<article class="center_column">
<header class="timeline_header">
<ul class="header_items">
<li class="item toots view">
<a id="toots_link">
Favourites
</a>
</li>
</ul>
</header>
<div id="js-stream_update">
<button>
View <span></span> new Toots
</button>
</div>
<ul id="js-timeline" class="timeline">
</ul>
<footer id="js-timeline_footer" class="timeline_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
<aside class="right_column">
<section class="side_widgets_wrap">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
</section>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
</div>
</main>
<script>
// namespace
current_file = location.pathname;
$("#js-profile_nav_favourites").toggleClass("view");
$("#js-profile_nav_toots > a").attr('href', './'+location.search);
$("#js-profile_nav_following > a").attr('href', 'following'+location.search);
$("#js-profile_nav_followers > a").attr('href', 'followers'+location.search);
$("#js-profile_nav_favourites > a").attr('href', 'favourites'+location.search);
<?php if (isset($_GET['mid'])): ?>
$(function() {
// find by mid
const account_id = <?php echo $_GET['mid']; ?>;
api.get('accounts/'+account_id, function(AccountObj) {
if ( AccountObj !== null ) {
setAccount(AccountObj);
setTimeline("favourites");
setRecentImages(AccountObj.id);
} else {
location.href = "/404.php";
}
});
});
<?php elseif((isset($_GET['user']))): ?>
$(function(){
// find by url
<?php
$name = preg_split("/@/", $_GET['user'])[1];
$domain = preg_split("/@/", $_GET['user'])[2];
$url = "https://$domain/@$name";
?>
const query = '<?= htmlspecialchars((string)filter_input(INPUT_GET, 'user'), ENT_QUOTES) ?>';
api.get('search', [{name:'q',data:query},{name:'resolve',data:'true'}], function(search) {
if ( !search.accounts.length ) {
location.href="/404.php";
} else if ( "@"+search.accounts[0].acct === query ) {
setAccount(search.accounts[0]);
setTimeline("favourites");
setRecentImages(search.accounts[0]);
} else {
location.href="/404.php";
}
});
})
<?php endif; ?>
</script>
<?php include ('footer.php'); ?>

View File

@ -1,115 +0,0 @@
<?php include ('header.php'); ?>
<!-- MAIN -->
<main id="main">
<?php include dirname(__FILE__).('/widgets/user_header.php'); ?>
<div class="article_wrap">
<aside class="left_column">
<div class="profile_icon_box">
<img id="js_profile_image" src="/assets/images/missing.png" mediaaccess="true"/>
</div>
<section class="profile_section_wrap">
<h1 class="profile_displayname">
<a id="js_profile_displayname" class="emoji_poss" href="#"></a>
</h1>
<h2 class="profile_username">
@<a id="js_profile_username" href="#"></a>
</h2>
<p id="js_profile_bio" class="profile_bio emoji_poss"></p>
<?php include dirname(__FILE__).('/widgets/user_recent_images.php'); ?>
</section>
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
<article class="center_column">
<div id="js-follows_profile">
</div>
<footer id="js-follows_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
</div>
</main>
<script>
// namespace
current_file = location.pathname;
$("#js-profile_nav_followers").toggleClass("view");
$("#js-profile_nav_toots > a").attr('href', './'+location.search);
$("#js-profile_nav_following > a").attr('href', 'following'+location.search);
$("#js-profile_nav_followers > a").attr('href', 'followers'+location.search);
$("#js-profile_nav_favourites > a").attr('href','favourites'+location.search);
<?php if (isset($_GET['mid'])): ?>
$(function() {
// find by mid
const account_id = <?= htmlspecialchars((string)filter_input(INPUT_GET, 'mid'), ENT_QUOTES) ?>;
api.get('accounts/'+account_id, function(AccountObj) {
if ( AccountObj !== null ) {
setAccount(AccountObj);
setFollows(account_id,'followers',[{name:'limit',data:18}]);
setRecentImages(AccountObj.id);
} else {
location.href="/404.php";
}
});
});
<?php elseif((isset($_GET['user']))): ?>
$(function(){
// find by url
<?php
$name = preg_split("/@/", $_GET['user'])[1];
$domain = preg_split("/@/", $_GET['user'])[2];
$url = "https://$domain/@$name";
?>
const query = '<?= htmlspecialchars((string)filter_input(INPUT_GET, 'user'), ENT_QUOTES) ?>';
api.get('search', [{name:'q',data:query},{name:'resolve',data:'true'}], function(search) {
if ( !search.accounts.length ) {
location.href="/404.php";
} else if ( "@"+search.accounts[0].acct === query ) {
setAccount(search.accounts[0]);
setFollows(search.accounts[0].id,'followers',[{name:'limit',data:18}]);
setRecentImages(search.accounts[0].id);
} else {
location.href="/404.php";
}
});
})
<?php endif; ?>
</script>
<?php include ('footer.php'); ?>

View File

@ -1,115 +0,0 @@
<?php include ('header.php'); ?>
<!-- MAIN -->
<main id="main">
<?php include dirname(__FILE__).('/widgets/user_header.php'); ?>
<div class="article_wrap">
<aside class="left_column">
<div class="profile_icon_box">
<img id="js_profile_image" src="/assets/images/missing.png" mediaaccess="true"/>
</div>
<section class="profile_section_wrap">
<h1 class="profile_displayname">
<a id="js_profile_displayname" class="emoji_poss" href="#"></a>
</h1>
<h2 class="profile_username">
@<a id="js_profile_username" href="#"></a>
</h2>
<p id="js_profile_bio" class="profile_bio emoji_poss"></p>
<?php include dirname(__FILE__).('/widgets/user_recent_images.php'); ?>
</section>
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
<article class="center_column">
<div id="js-follows_profile">
</div>
<footer id="js-follows_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
</div>
</main>
<script>
// namespace
current_file = location.pathname;
$("#js-profile_nav_following").toggleClass("view");
$("#js-profile_nav_toots > a").attr('href', './'+location.search);
$("#js-profile_nav_following > a").attr('href', 'following'+location.search);
$("#js-profile_nav_followers > a").attr('href', 'followers'+location.search);
$("#js-profile_nav_favourites > a").attr('href','favourites'+location.search);
<?php if (isset($_GET['mid'])): ?>
$(function() {
// find by mid
const account_id = <?= htmlspecialchars((string)filter_input(INPUT_GET, 'mid'), ENT_QUOTES) ?>;
api.get('accounts/'+account_id, function(AccountObj) {
if ( AccountObj !== null ) {
setAccount(AccountObj);
setFollows(account_id,'following',[{name:'limit',data:18}]);
setRecentImages(AccountObj.id);
} else {
location.href="/404.php";
}
});
});
<?php elseif((isset($_GET['user']))): ?>
$(function(){
// find by url
<?php
$name = preg_split("/@/", $_GET['user'])[1];
$domain = preg_split("/@/", $_GET['user'])[2];
$url = "https://$domain/@$name";
?>
const query = '<?= htmlspecialchars((string)filter_input(INPUT_GET, 'user'), ENT_QUOTES) ?>';
api.get('search', [{name:'q',data:query},{name:'resolve',data:'true'}], function(search) {
if ( !search.accounts.length ) {
location.href="/404.php";
} else if ( "@"+search.accounts[0].acct === query ) {
setAccount(search.accounts[0]);
setFollows(search.accounts[0].id,'following',[{name:'limit',data:18}]);
setRecentImages(search.accounts[0].id);
} else {
location.href="/404.php";
}
});
})
<?php endif; ?>
</script>
<?php include ('footer.php'); ?>

View File

@ -1,159 +0,0 @@
<?php include ('header.php'); ?>
<!-- MAIN -->
<main id="main">
<?php include dirname(__FILE__).('/widgets/user_header.php'); ?>
<div class="article_wrap">
<aside class="left_column">
<div class="profile_icon_box">
<img id="js_profile_image" src="/assets/images/missing.png" mediaaccess="true"/>
</div>
<section class="profile_section_wrap">
<h1 class="profile_displayname">
<a id="js_profile_displayname" class="emoji_poss" href="#"></a>
</h1>
<h2 class="profile_username">
@<a id="js_profile_username" href="#"></a>
</h2>
<p id="js_profile_bio" class="profile_bio emoji_poss"></p>
<?php include dirname(__FILE__).('/widgets/user_recent_images.php'); ?>
</section>
<div class="right_column_clone">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</div>
</aside>
<article class="center_column">
<header class="timeline_header">
<ul class="header_items">
<li class="item toots">
<a id="toots_link">
Toots
</a>
</li>
<li class="item wreplies view">
<a id="with_replies_link">
Toots &amp; replies
</a>
</li>
<li class="item media">
<a id="media_link">
Media
</a>
</li>
</ul>
</header>
<div id="js-stream_update">
<button>
View <span></span> new Toots
</button>
</div>
<ul id="js-timeline" class="timeline">
</ul>
<footer id="js-timeline_footer" class="timeline_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
<aside class="right_column">
<section class="side_widgets_wrap">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
</section>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
</div>
</main>
<script>
// namespace
current_file = location.pathname;
$("#toots_link").attr('href', './'+location.search);
$("#with_replies_link").attr('href', './with_replies'+location.search);
$("#media_link").attr('href', './media'+location.search);
$("#js-profile_nav_toots > a").toggleClass("view");
$("#js-profile_nav_toots > a").attr('href', location.pathname+location.search);
$("#js-profile_nav_following > a").attr('href', './following'+location.search);
$("#js-profile_nav_followers > a").attr('href', './followers'+location.search);
$("#js-profile_nav_favourites > a").attr('href', './favourites'+location.search);
<?php if (isset($_GET['mid'])): ?>
$(function() {
// find by mid
const account_id = <?= htmlspecialchars((string)filter_input(INPUT_GET, 'mid'), ENT_QUOTES) ?>;
api.get('accounts/'+account_id, function(AccountObj) {
if ( AccountObj !== null ) {
setAccount(AccountObj);
setTimeline("accounts/"+AccountObj.id+"/statuses");
setRecentImages(AccountObj.id);
} else {
location.href = "/404.php";
}
});
});
<?php elseif((isset($_GET['user']))): ?>
$(function(){
// find by url
<?php
$name = preg_split("/@/", $_GET['user'])[1];
$domain = preg_split("/@/", $_GET['user'])[2];
$url = "https://$domain/@$name";
?>
const query = '<?= htmlspecialchars((string)filter_input(INPUT_GET, 'user'), ENT_QUOTES) ?>';
api.get('search', [{name:'q',data:query},{name:'resolve',data:'true'}], function(search) {
if ( !search.accounts.length ) {
location.href = "/404.php";
} else if ( "@"+search.accounts[0].acct === query ) {
setAccount(search.accounts[0]);
setTimeline("accounts/"+search.accounts[0].id+"/statuses");
setRecentImages(search.accounts[0].id);
} else {
location.href = "/404.php";
}
});
})
<?php endif; ?>
</script>
<?php include ('footer.php'); ?>

View File

@ -1,160 +0,0 @@
<?php include ('header.php'); ?>
<!-- MAIN -->
<main id="main">
<?php include dirname(__FILE__).('/widgets/user_header.php'); ?>
<div class="article_wrap">
<aside class="left_column">
<div class="profile_icon_box">
<img id="js_profile_image" src="/assets/images/missing.png" mediaaccess="true"/>
</div>
<section class="profile_section_wrap">
<h1 class="profile_displayname">
<a id="js_profile_displayname" class="emoji_poss" href="#"></a>
</h1>
<h2 class="profile_username">
@<a id="js_profile_username" href="#"></a>
</h2>
<p id="js_profile_bio" class="profile_bio emoji_poss"></p>
<?php include dirname(__FILE__).('/widgets/user_recent_images.php'); ?>
</section>
<div class="right_column_clone">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</div>
</aside>
<article class="center_column">
<header class="timeline_header">
<ul class="header_items">
<li class="item toots">
<a id="toots_link">
Toots
</a>
</li>
<li class="item wreplies">
<a id="with_replies_link">
Toots &amp; replies
</a>
</li>
<li class="item media view">
<a id="media_link">
Media
</a>
</li>
</ul>
</header>
<div id="js-stream_update">
<button>
View <span></span> new Toots
</button>
</div>
<ul id="js-timeline" class="timeline">
</ul>
<footer id="js-timeline_footer" class="timeline_footer">
<i class="fa fa-spin fa-circle-o-notch" aria-hidden="true"></i>
</footer>
</article>
<aside class="right_column">
<section class="side_widgets_wrap">
<?php include dirname(__FILE__).('/widgets/side_who_to_follow.php'); ?>
</section>
<?php include dirname(__FILE__).('/widgets/side_footer.php'); ?>
</aside>
</div>
</main>
<script>
// namespace
current_file = location.pathname;
$("#toots_link").attr('href', './'+location.search);
$("#with_replies_link").attr('href', './with_replies'+location.search);
$("#media_link").attr('href', './media'+location.search);
$("#js-profile_nav_toots > a").toggleClass("view");
$("#js-profile_nav_toots > a").attr('href', location.pathname+location.search);
$("#js-profile_nav_following > a").attr('href', './following'+location.search);
$("#js-profile_nav_followers > a").attr('href', './followers'+location.search);
$("#js-profile_nav_favourites > a").attr('href', './favourites'+location.search);
<?php if (isset($_GET['mid'])): ?>
$(function() {
// find by mid
const account_id = <?= htmlspecialchars((string)filter_input(INPUT_GET, 'mid'), ENT_QUOTES) ?>;
api.get('accounts/'+account_id, function(AccountObj) {
if ( AccountObj !== null ) {
setAccount(AccountObj);
setTimeline("accounts/"+AccountObj.id+"/statuses",[{name:'only_media',data:'true'}]);
setRecentImages(AccountObj.id);
} else {
location.href = "/404.php";
}
});
});
<?php elseif((isset($_GET['user']))): ?>
$(function(){
// find by url
<?php
$name = preg_split("/@/", $_GET['user'])[1];
$domain = preg_split("/@/", $_GET['user'])[2];
$url = "https://$domain/@$name";
?>
const query = '<?= htmlspecialchars((string)filter_input(INPUT_GET, 'user'), ENT_QUOTES) ?>';
api.get('search', [{name:'q',data:query},{name:'resolve',data:'true'}], function(search) {
if ( !search.accounts.length ) {
location.href="/404.php";
} else if ( "@"+search.accounts[0].acct === query ) {
setAccount(search.accounts[0]);
setTimeline("accounts/"+search.accounts[0].id+"/statuses",[{name:'only_media',data:'true'}]);
setRecentImages(search.accounts[0].id);
} else {
location.href="/404.php";
}
});
})
<?php endif; ?>
</script>
<?php include ('footer.php'); ?>

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