making a lot of progress on the js side

This commit is contained in:
flash 2016-08-04 01:40:47 +02:00
parent 3d8c30e8b6
commit deecbbaf0f
33 changed files with 533 additions and 826 deletions

View file

@ -0,0 +1,22 @@
<?php
/**
* Holds the status controller.
*
* @package Sakura
*/
namespace Sakura\Controllers;
/**
* The status page and related stuff.
*
* @package Sakura
* @author Julian van de Groep <me@flash.moe>
*/
class StatusController extends Controller
{
public function index()
{
return view('status/index');
}
}

View file

@ -90,10 +90,20 @@ class Template
$views_dir = ROOT . 'resources/views/';
// Initialise Twig Filesystem Loader
$twigLoader = new Twig_Loader_Filesystem([$views_dir . self::$name, $views_dir . 'shared/']);
$loader = new Twig_Loader_Filesystem();
foreach (glob("{$views_dir}*") as $dir) {
$key = basename($dir);
if ($key === self::$name) {
$key = '__main__';
}
$loader->addPath($dir, $key);
}
// Environment variable
$twigEnv = [
$env = [
'cache' => config("performance.template_cache")
? realpath(ROOT . config("performance.cache_dir") . 'views')
: false,
@ -102,7 +112,7 @@ class Template
];
// And now actually initialise the templating engine
self::$engine = new Twig_Environment($twigLoader, $twigEnv);
self::$engine = new Twig_Environment($loader, $env);
// Load String template loader
self::$engine->addExtension(new Twig_Extension_StringLoader());

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 KiB

View file

@ -0,0 +1,17 @@
/// <reference path="Sakura/AJAX.ts" />
/// <reference path="Sakura/Changelog.ts" />
/// <reference path="Sakura/Comments.ts" />
/// <reference path="Sakura/Config.ts" />
/// <reference path="Sakura/Cookies.ts" />
/// <reference path="Sakura/DOM.ts" />
/// <reference path="Sakura/Friend.ts" />
/// <reference path="Sakura/HTTPMethod.ts" />
/// <reference path="Sakura/IChangelogAction.ts" />
/// <reference path="Sakura/IChangelogChange.ts" />
/// <reference path="Sakura/IChangelogContributor.ts" />
/// <reference path="Sakura/IChangelogDate.ts" />
/// <reference path="Sakura/IChangelogRelease.ts" />
/// <reference path="Sakura/IFriendResponse.ts" />
/// <reference path="Sakura/INotification.ts" />
/// <reference path="Sakura/Notifications.ts" />
/// <reference path="Sakura/TimeAgo.ts" />

View file

@ -3,7 +3,7 @@ namespace Sakura
export class Changelog
{
private static Client: AJAX;
private static Element: DOM;
private static Element: HTMLDivElement;
private static Fetch: number = 0;
private static Colours: string[] = [
'inherit', // Unknown
@ -15,25 +15,25 @@ namespace Sakura
'#C44', // Revert
];
public static Build(target: DOM)
public static Build(target: HTMLElement)
{
this.Client = new AJAX;
this.Element = DOM.Create('table', 'changelog panelTable');
this.Element = <HTMLDivElement>DOM.Create('table', 'changelog panelTable');
this.Element.Element.style.borderSpacing = '0 1px';
this.Element.style.borderSpacing = '0 1px';
var title: DOM = DOM.Create('div', 'head'),
link: DOM = DOM.Create('a', 'underline');
var title: HTMLDivElement = <HTMLDivElement>DOM.Create('div', 'head'),
link: HTMLLinkElement = <HTMLLinkElement>DOM.Create('a', 'underline');
title.Element.style.marginBottom = '1px';
title.style.marginBottom = '1px';
link.Text('Changelog');
(<HTMLLinkElement>link.Element).href = Config.ChangelogUrl + '#r' + Config.Revision;
(<HTMLLinkElement>link.Element).target = '_blank';
link.innerText = 'Changelog';
link.href = Config.ChangelogUrl + '#r' + Config.Revision;
link.target = '_blank';
title.Append(link);
target.Append(title);
target.Append(this.Element);
DOM.Append(title, link);
DOM.Append(target, title);
DOM.Append(target, this.Element);
this.Client.SetUrl(Config.ChangelogUrl + Config.ChangelogApi);
@ -53,34 +53,33 @@ namespace Sakura
private static Add(changelog: IChangelogDate)
{
var header: DOM = DOM.Create('tr', 'changelog__row changelog__row--header'),
headerInner: DOM = DOM.Create('th', 'changelog__header');
var header: HTMLTableRowElement = <HTMLTableRowElement>DOM.Create('tr', 'changelog__row changelog__row--header'),
headerInner: HTMLTableHeaderCellElement = <HTMLTableHeaderCellElement>DOM.Create('th', 'changelog__header');
headerInner.Text(changelog.date);
headerInner.Element.style.fontSize = '1.2em';
(<HTMLTableHeaderCellElement>headerInner.Element).colSpan = 2;
headerInner.innerText = changelog.date;
headerInner.style.fontSize = '1.2em';
headerInner.colSpan = 2;
header.Append(headerInner);
this.Element.Append(header);
DOM.Append(header, headerInner);
DOM.Append(this.Element, header);
for (var _i in changelog.changes)
{
var change: IChangelogChange = changelog.changes[_i],
row: DOM = DOM.Create('tr', 'changelog__row'),
action: DOM = DOM.Create('td', 'changelog__column'),
message: DOM = DOM.Create('td', 'changelog__column');
row: HTMLTableRowElement = <HTMLTableRowElement>DOM.Create('tr', 'changelog__row'),
action: HTMLTableCellElement = <HTMLTableCellElement>DOM.Create('td', 'changelog__column'),
message: HTMLTableCellElement = <HTMLTableCellElement>DOM.Create('td', 'changelog__column');
action.Text(change.action.name);
action.Element.style.backgroundColor = this.Colours[change.action.id];
action.Element.style.borderBottom = '1px solid ' + this.Colours[change.action.id];
action.innerText = change.action.name;
action.style.backgroundColor = this.Colours[change.action.id];
action.style.borderBottom = '1px solid ' + this.Colours[change.action.id];
message.Text(change.message);
message.Element.style.borderBottom = '1px solid ' + this.Colours[change.action.id];
message.innerText = change.message;
message.style.borderBottom = '1px solid ' + this.Colours[change.action.id];
row.Append(action);
row.Append(message);
this.Element.Append(row);
DOM.Append(row, action);
DOM.Append(row, message);
DOM.Append(this.Element, row);
}
}
}

View file

@ -5,9 +5,6 @@ namespace Sakura
public static Revision: number = 0;
public static UserId: number = 0;
public static SessionId: string = "";
public static UserNameMinLength: number = 3;
public static UserNameMaxLength: number = 16;
public static PasswordMinEntropy: number = 48;
public static LoggedIn: boolean = false;
public static ChangelogUrl: string = "https://sakura.flash.moe/";
public static ChangelogApi: string = "api.php/";

View file

@ -2,73 +2,186 @@ namespace Sakura
{
export class DOM
{
public Element: HTMLElement;
public static BEM(block: string, element: string = null, modifiers: string[] = [], firstModifierOnly: boolean = false): string
{
var className: string = "";
constructor(object: any, mode: DOMSelector) {
switch (mode) {
case DOMSelector.ID:
this.Element = document.getElementById(object);
break;
case DOMSelector.CLASS:
this.Element = <HTMLElement>document.getElementsByClassName(object)[0];
break;
case DOMSelector.ELEMENT:
this.Element = object;
break;
case DOMSelector.QUERY:
this.Element = <HTMLElement>document.querySelector(object);
break;
if (firstModifierOnly && modifiers.length === 0) {
return null;
}
className += block;
if (element !== null) {
className += "__" + element;
}
var baseName: string = className;
for (var _i in modifiers) {
if (firstModifierOnly) {
return baseName + "--" + modifiers[_i];
}
className += " " + baseName + "--" + modifiers[_i];
}
return className;
}
public static Create(element: string, className: string = null, id: string = null): DOM {
var elem: HTMLElement = document.createElement(element),
cont: DOM = new DOM(elem, DOMSelector.ELEMENT);
public static Create(name: string, className: string = null, id: string = null): HTMLElement {
var element = document.createElement(name);
if (className !== null) {
cont.SetClass(className);
element.className = className;
}
if (id !== null) {
cont.SetId(id);
element.id = id;
}
return cont;
return element;
}
public Text(text: string): void {
this.Element.appendChild(document.createTextNode(text));
public static Text(text: string): Text {
return document.createTextNode(text);
}
public Append(element: DOM): void {
this.Element.appendChild(element.Element);
public static ID(id: string): HTMLElement {
return document.getElementById(id);
}
public Prepend(element: DOM, before: HTMLElement | Node = null): void {
public static Remove(element: HTMLElement): void {
element.parentNode.removeChild(element);
}
public static Class(className: string): NodeListOf<HTMLElement> {
return <NodeListOf<HTMLElement>>document.getElementsByClassName(className);
}
public static Prepend(target: HTMLElement, element: HTMLElement | Text, before: HTMLElement | Node = null): void {
if (before === null) {
before = this.Element.firstChild;
before = target.firstChild;
}
if (this.Element.children.length) {
this.Element.insertBefore(element.Element, before);
if (target.children.length) {
target.insertBefore(element, before);
} else {
this.Append(element);
this.Append(target, element);
}
}
public SetId(id: string): void {
this.Element.id = id;
public static Append(target: HTMLElement, element: HTMLElement | Text): void {
target.appendChild(element);
}
public SetClass(name: string): void {
this.Element.className = name;
public static ClassNames(target: HTMLElement): string[] {
var className: string = target.className,
classes: string[] = [];
if (className.length > 1) {
classes = className.split(' ');
}
return classes;
}
public Remove(): void {
this.Element.parentNode.removeChild(this.Element);
public static AddClass(target: HTMLElement, classes: string[]): void {
for (var _i in classes) {
var current: string[] = this.ClassNames(target),
index: number = current.indexOf(classes[_i]);
if (index >= 0) {
continue;
}
current.push(classes[_i]);
target.className = current.join(' ');
}
}
public static RemoveClass(target: HTMLElement, classes: string[]): void {
for (var _i in classes) {
var current: string[] = this.ClassNames(target),
index: number = current.indexOf(classes[_i]);
if (index < 0) {
continue;
}
current.splice(index, 1);
target.className = current.join(' ');
}
}
public static Clone(subject: HTMLElement): HTMLElement {
return (<HTMLElement>subject.cloneNode(true));
}
public static Query(query: string): NodeListOf<Element> {
return document.querySelectorAll(query);
}
public static SetPosition(element: HTMLTextAreaElement, pos: number, end: boolean = false): void {
if (end) {
element.selectionEnd = pos;
return;
}
element.selectionStart = pos;
}
public static GetPosition(element: HTMLTextAreaElement, end: boolean = false): number {
if (end) {
return element.selectionEnd;
}
return element.selectionStart;
}
public static GoToStart(element: HTMLTextAreaElement): void {
this.SetPosition(element, 0);
}
public static GoToEnd(element: HTMLTextAreaElement): void {
this.SetPosition(element, element.value.length);
}
public static GetSelectionLength(element: HTMLTextAreaElement): number {
var length: number = this.GetPosition(element, true) - this.GetPosition(element);
if (length < 0) {
length = this.GetPosition(element) - this.GetPosition(element, true);
}
return length;
}
public static EnterAtCursor(element: HTMLTextAreaElement, text: string, overwrite: boolean = false): void {
var value: string = this.GetText(element),
final: string = "",
current: number = this.GetPosition(element);
final += value.slice(0, current);
final += text;
final += value.slice(current + (overwrite ? text.length : 0));
this.SetText(element, final);
this.SetPosition(element, current);
}
public static GetSelectedText(element: HTMLTextAreaElement): string {
return this.GetText(element).slice(this.GetPosition(element), this.GetPosition(element, true));
}
public static GetText(element: HTMLTextAreaElement): string {
return element.value;
}
public static SetText(element: HTMLTextAreaElement, text: string): void {
element.value = text;
}
}
}

View file

@ -1,10 +0,0 @@
namespace Sakura
{
export enum DOMSelector
{
ID,
CLASS,
ELEMENT,
QUERY
}
}

View file

@ -1,5 +1,3 @@
declare var ajaxBusyView: any;
namespace Sakura
{
export class Friend
@ -28,18 +26,22 @@ namespace Sakura
this.Client.SetSend({ "session": Config.SessionId });
this.Client.AddCallback(200, (client: AJAX) => {
var response: IFriendResponse = <IFriendResponse>client.JSON(),
error: string = response.error || null;
alert: INotification = {
id: -(Date.now()),
user: Config.UserId,
time: Math.round(Date.now() / 1000),
read: false,
title: response.error || response.message,
text: "",
link: null,
image: "FONT:fa-user-plus",
timeout: 60000
};
if (error !== null) {
ajaxBusyView(true, error, 'fail');
Notifications.DisplayMethod.call(this, alert);
setTimeout(() => {
ajaxBusyView(false);
}, 1500);
} else {
ajaxBusyView(true, response.message, 'ok');
location.reload();
}
// replace this with a thing that just updates the dom
window.location.reload();
});
this.Client.Start(HTTPMethod.POST);
}

View file

@ -1,76 +0,0 @@
declare function escape(a);
namespace Sakura
{
export class Legacy
{
// Alternative for Math.log2() since it's still experimental
public static log2(num: number): number {
return Math.log(num) / Math.log(2);
}
// Get the number of unique characters in a string
public static unique(string: string): number {
// Store the already found character
var used: string[] = [];
// The amount of characters we've already found
var count: number = 0;
// Count the amount of unique characters
for (var i = 0; i < string.length; i++) {
// Check if we already counted this character
if (used.indexOf(string[i]) == -1) {
// Push the character into the used array
used.push(string[i]);
// Up the count
count++;
}
}
// Return the count
return count;
}
// Calculate password entropy
public static entropy(string: string): number {
// Decode utf-8 encoded characters
string = this.utf8_decode(string);
// Count the unique characters in the string
var unique: number = this.unique(string);
// Do the entropy calculation
return unique * this.log2(256);
}
// Validate string lengths
public static stringLength(string: string, minimum: number, maximum: number): boolean {
// Get length of string
var length = string.length;
// Check if it meets the minimum/maximum
if (length < minimum || length > maximum) {
return false;
}
// If it passes both return true
return true;
}
// Validate email address formats
public static validateEmail(email: string): boolean {
// RFC compliant e-mail address regex
var re = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,48})+$/;
// Test it on the email var which'll return a boolean
return re.test(email);
}
// Decode a utf-8 string
public static utf8_decode(string): string {
return decodeURIComponent(escape(string));
}
}
}

View file

@ -1,16 +0,0 @@
namespace Sakura
{
export class Main
{
public static Startup(): void {
console.log(this.Supported());
TimeAgo.Init();
Friend.Init();
Notifications.Init();
}
public static Supported(): boolean {
return true;
}
}
}

View file

@ -4,19 +4,17 @@ namespace Sakura
{
private static Client: AJAX;
private static IntervalContainer: number;
public static DisplayMethod: Function = (alert: INotification) => {
console.log(alert);
};
public static DisplayMethod: Function = Notifications.Display;
public static Init(): void
{
this.Client = new AJAX;
this.Client.SetUrl("/notifications");
this.Client.AddCallback(200, (client: AJAX) => {
Notifications.Client = new AJAX;
Notifications.Client.SetUrl("/notifications");
Notifications.Client.AddCallback(200, (client: AJAX) => {
Notifications.Load(<INotification[]>client.JSON());
});
this.Poll();
this.Start();
Notifications.Poll();
Notifications.Start();
}
public static Poll(): void
@ -32,7 +30,7 @@ namespace Sakura
}
Notifications.Poll();
}, 5000);
}, 60000);
}
public static Stop(): void
@ -47,5 +45,10 @@ namespace Sakura
this.DisplayMethod(alerts[i]);
}
}
public static Display(alert: INotification): void
{
console.log(alert);
}
}
}

View file

@ -6,7 +6,7 @@ namespace Sakura
public static Init(): void
{
var watchElements: NodeListOf<Element> = document.getElementsByClassName(this.WatchClass);
var watchElements: NodeListOf<Element> = DOM.Class(this.WatchClass);
for (var _i in watchElements) {
if ((typeof watchElements[_i]).toLowerCase() !== 'object') {

View file

@ -0,0 +1,6 @@
/// <reference path="Yuuno/Busy.ts" />
/// <reference path="Yuuno/BusyMode.ts" />
/// <reference path="Yuuno/Editor.ts" />
/// <reference path="Yuuno/Main.ts" />
/// <reference path="Yuuno/Notifications.ts" />
/// <reference path="Yuuno/Ybabstat.ts" />

View file

@ -0,0 +1,47 @@
namespace Yuuno
{
export class Busy
{
private static Container: HTMLElement;
private static Text: HTMLElement;
private static Icon: HTMLElement;
public static Init(): void
{
this.Container = Sakura.DOM.ID('busy-window');
this.Text = Sakura.DOM.ID('busy-status');
this.Icon = Sakura.DOM.ID('busy-icon');
}
public static Hide(): void
{
Sakura.DOM.AddClass(this.Container, ['hidden']);
}
public static Show(mode: BusyMode = BusyMode.BUSY, text: string = null, hideAfter: number = 0): void
{
var icon: string = "fa fa-4x ";
switch (mode) {
case BusyMode.OK:
icon += 'fa-check';
break;
case BusyMode.FAIL:
icon += 'fa-remove';
break;
case BusyMode.BUSY:
default:
icon += 'fa-refresh fa-spin';
}
Sakura.DOM.RemoveClass(this.Icon, Sakura.DOM.ClassNames(this.Icon));
Sakura.DOM.AddClass(this.Icon, icon.split(' '));
this.Text.innerText = text || '';
Sakura.DOM.RemoveClass(this.Container, ['hidden']);
if (hideAfter > 0) {
setTimeout(Busy.Hide, hideAfter);
}
}
}
}

View file

@ -0,0 +1,9 @@
namespace Yuuno
{
export enum BusyMode
{
OK,
FAIL,
BUSY
}
}

View file

@ -0,0 +1,20 @@
/// <reference path="../Sakura.ts" />
namespace Yuuno
{
export class Editor
{
public static InsertBBCode(target: HTMLTextAreaElement, code: string, param: boolean): void
{
var start: string = "[" + code + (param ? "=" : "") + "]",
end: string = "[/" + code + "]",
selectionLength = Sakura.DOM.GetSelectionLength(target);
Sakura.DOM.EnterAtCursor(target, start);
Sakura.DOM.SetPosition(target, Sakura.DOM.GetPosition(target) + selectionLength + start.length);
Sakura.DOM.EnterAtCursor(target, end);
Sakura.DOM.SetPosition(target, Sakura.DOM.GetPosition(target) - selectionLength);
Sakura.DOM.SetPosition(target, Sakura.DOM.GetPosition(target) + selectionLength, true);
}
}
}

View file

@ -1,28 +1,75 @@
/// <reference path="../Sakura/INotification.ts" />
/// <reference path="../Sakura.ts" />
namespace Yuuno
{
export class Notifications
export class Notifications extends Sakura.Notifications
{
private static Container;
private static Container: HTMLElement;
public static RegisterDisplay(): void
public static Init(): void
{
this.Container = new Sakura.DOM('notifications', Sakura.DOMSelector.ID);
Sakura.Notifications.DisplayMethod = this.Display;
super.Init();
Notifications.Container = Sakura.DOM.ID('notifications');
}
public static Display(alert: Sakura.INotification): void
{
var id = 'yuuno-alert-' + Date.now(),
container = Sakura.DOM.Create('div', 'notification-enter', id),
icon = Sakura.DOM.Create('div', 'notification-icon'),
inner = Sakura.DOM.Create('div', 'notification-content'),
title = Sakura.DOM.Create('div', 'notification-title'),
text = Sakura.DOM.Create('div', 'notification-text'),
close = Sakura.DOM.Create('div', 'notification-close'),
closeIcon = Sakura.DOM.Create('div'),
clear = Sakura.DOM.Create('div');
container: HTMLDivElement = <HTMLDivElement>Sakura.DOM.Create('div', 'notification-enter', id),
iconContent: HTMLDivElement = <HTMLDivElement>Sakura.DOM.Create('div'),
icon: HTMLDivElement = <HTMLDivElement>Sakura.DOM.Create('div', 'notification-icon'),
inner: HTMLDivElement = <HTMLDivElement>Sakura.DOM.Create('div', 'notification-content'),
title: HTMLDivElement = <HTMLDivElement>Sakura.DOM.Create('div', 'notification-title'),
text: HTMLDivElement = <HTMLDivElement>Sakura.DOM.Create('div', 'notification-text'),
close: HTMLDivElement = <HTMLDivElement>Sakura.DOM.Create('div', 'notification-close'),
closeIcon: HTMLDivElement = <HTMLDivElement>Sakura.DOM.Create('div');
if (alert.image === null) {
Sakura.DOM.AddClass(iconContent, ['font-icon', 'fa', 'fa-info', 'fa-4x']);
} else if (alert.image.substring(0, 5) == 'FONT:') {
Sakura.DOM.AddClass(iconContent, ['font-icon', 'fa', alert.image.replace('FONT:', ''), 'fa-4x']);
} else {
iconContent.style.background = "url(0) no-repeat center center / cover transparent".replace('0', alert.image);
iconContent.style.width = "100%";
iconContent.style.height = "100%";
}
Sakura.DOM.Append(icon, iconContent);
Sakura.DOM.Append(container, icon);
title.innerText = alert.title;
text.innerText = alert.text;
if (alert.link !== null) {
inner.setAttribute('onclick', alert.link.substr(0, 11) == 'javascript:' ? alert.link.substring(11) : 'window.location.assign("' + alert.link + '");');
}
Sakura.DOM.Append(inner, title);
Sakura.DOM.Append(inner, text);
Sakura.DOM.Append(container, inner);
close.setAttribute('onclick', 'Yuuno.Notifications.CloseAlert(this.parentNode.id);');
Sakura.DOM.Append(close, closeIcon);
Sakura.DOM.Append(container, close);
Sakura.DOM.Append(Notifications.Container, container);
if (alert.timeout > 0) {
setTimeout(() => {
Notifications.CloseAlert(id);
}, alert.timeout);
}
}
private static CloseAlert(id: string): void
{
var element: HTMLElement = Sakura.DOM.ID(id);
Sakura.DOM.AddClass(element, ['notification-exit']);
setTimeout(() => {
Sakura.DOM.Remove(element);
}, 410);
}
}
}

View file

@ -1,11 +1,19 @@
/// <reference path="../Sakura.ts" />
namespace Yuuno
{
export class Main
{
public static Startup()
{
Sakura.Main.Startup();
Notifications.RegisterDisplay();
Sakura.TimeAgo.Init();
Sakura.Friend.Init();
Notifications.Init();
Busy.Init();
if (window.location.pathname === '/' || window.location.pathname === '/forum' || window.location.pathname === '/forum/') {
Ybabstat.Initiate();
}
}
}
}

View file

@ -1,68 +1,82 @@
var illuminati: Array<number> = new Array<number>();
var startTime: number = (new Date()).getTime();
/// <reference path="../Sakura.ts" />
function hideYourMind(conflictions: KeyboardEvent): void {
var twoThousandTwelveIsTheYearWeAscendToSpaceRobots: number = conflictions.keyCode;
namespace Yuuno
{
export class Ybabstat
{
private static Illuminati: number[] = [];
private static FreeMason: number = Date.now();
illuminati.push(twoThousandTwelveIsTheYearWeAscendToSpaceRobots);
public static Initiate(): void
{
document.addEventListener('keydown', Ybabstat.HideYourMind);
}
if (illuminati[0] == 68 && illuminati[1] == 73 && illuminati[2] == 67 && illuminati[3] == 75 && illuminati[4] == 83) {
var dicksAre: HTMLAudioElement = document.createElement('audio');
var forMyFriends: HTMLSourceElement = document.createElement('source');
var whenTheyCome: HTMLSourceElement = document.createElement('source');
private static TwoThousandSixteenIsTheYearWePhysicallyMergeWithCats(): void
{
var diff: number = Date.now() - Ybabstat.FreeMason,
vals: number[] = [
-7 / Math.cos((diff / 500) * (.85 * Math.PI)),
-7 * Math.tan((diff / 250) * (.85 * Math.PI))
];
forMyFriends.type = 'audio/mp3';
whenTheyCome.type = 'audio/ogg';
document.body.style.position = 'absolute';
document.body.style.left = vals[0] + 'px';
document.body.style.top = vals[1] + 'px';
document.body.style.fontSize = vals[0] + 'px';
}
forMyFriends.src = 'https://data.flashii.net/sounds/dicks.mp3';
whenTheyCome.src = 'https://data.flashii.net/sounds/dicks.ogg';
private static HideYourMind(conflictions: KeyboardEvent): void
{
var twoThousandTwelveIsTheYearWeAscendToSpaceRobots: number = conflictions.keyCode;
dicksAre.appendChild(forMyFriends);
dicksAre.appendChild(whenTheyCome);
Ybabstat.Illuminati.push(twoThousandTwelveIsTheYearWeAscendToSpaceRobots);
var toMyHouse: HTMLAudioElement = dicksAre;
if (Ybabstat.Illuminati[0] === 68 && Ybabstat.Illuminati[1] === 73 && Ybabstat.Illuminati[2] === 67 && Ybabstat.Illuminati[3] === 75 && Ybabstat.Illuminati[4] === 83) {
var dicksAreForMy: HTMLAudioElement = <HTMLAudioElement>Sakura.DOM.Create('audio'),
friendsWhenThey: HTMLSourceElement = <HTMLSourceElement>Sakura.DOM.Create('source'),
comeToMyHouse: HTMLSourceElement = <HTMLSourceElement>Sakura.DOM.Create('source');
toMyHouse.play();
friendsWhenThey.type = 'audio/mp3';
comeToMyHouse.type = 'audio/ogg';
illuminati = new Array<number>();
}
friendsWhenThey.src = 'https://data.flashii.net/assets/sounds/dicks.mp3';
comeToMyHouse.src = 'https://data.flashii.net/assets/sounds/dicks.ogg';
if (illuminati[0] == 77 && illuminati[1] == 69 && illuminati[2] == 87 && illuminati[3] == 79 && illuminati[4] == 87) {
var noklz: HTMLAudioElement = document.createElement('audio');
var von: HTMLSourceElement = document.createElement('source');
var schnitzel: HTMLSourceElement = document.createElement('source');
Sakura.DOM.Append(dicksAreForMy, friendsWhenThey);
Sakura.DOM.Append(dicksAreForMy, comeToMyHouse);
von.type = 'audio/mp3';
schnitzel.type = 'audio/ogg';
dicksAreForMy.play();
von.src = 'https://data.flashii.net/sounds/mewow.mp3';
schnitzel.src = 'https://data.flashii.net/sounds/mewow.ogg';
Ybabstat.Illuminati = [];
}
noklz.appendChild(von);
noklz.appendChild(schnitzel);
if (Ybabstat.Illuminati[0] === 77 && Ybabstat.Illuminati[1] === 69 && Ybabstat.Illuminati[2] === 87 && Ybabstat.Illuminati[3] === 79 && Ybabstat.Illuminati[4] === 87) {
var noklz: HTMLAudioElement = <HTMLAudioElement>Sakura.DOM.Create('audio'),
von: HTMLSourceElement = <HTMLSourceElement>Sakura.DOM.Create('source'),
schnitzel: HTMLSourceElement = <HTMLSourceElement>Sakura.DOM.Create('source');
noklz.play();
von.type = 'audio/mp3';
schnitzel.type = 'audio/ogg';
document.body.style.animation = 'spin 5s infinite linear';
von.src = 'https://data.flashii.net/assets/sounds/mewow.mp3';
schnitzel.src = 'https://data.flashii.net/assets/sounds/mewow.ogg';
illuminati = new Array<number>();
}
Sakura.DOM.Append(noklz, von);
Sakura.DOM.Append(noklz, schnitzel);
if (illuminati[0] == 83 && illuminati[1] == 79 && illuminati[2] == 67 && illuminati[3] == 75 && illuminati[4] == 67 && illuminati[5] == 72 && illuminati[6] == 65 && illuminati[7] == 84) {
setInterval(twoThousandSixteenIsTheYearWePhysicallyMergeWithCats, 20);
noklz.play();
illuminati = new Array<number>();
document.body.style.animation = 'spin 5s infinite linear';
Ybabstat.Illuminati = [];
}
if (Ybabstat.Illuminati[0] == 83 && Ybabstat.Illuminati[1] == 79 && Ybabstat.Illuminati[2] == 67 && Ybabstat.Illuminati[3] == 75 && Ybabstat.Illuminati[4] == 67 && Ybabstat.Illuminati[5] == 72 && Ybabstat.Illuminati[6] == 65 && Ybabstat.Illuminati[7] == 84) {
setInterval(Ybabstat.TwoThousandSixteenIsTheYearWePhysicallyMergeWithCats, 20);
Ybabstat.Illuminati = [];
}
}
}
}
function twoThousandSixteenIsTheYearWePhysicallyMergeWithCats() {
var diff: number = (new Date()).getTime() - startTime;
var vals: Array<number> = [-7 / Math.cos((diff / 500) * (.85 * Math.PI)), -7 * Math.tan((diff / 250) * (.85 * Math.PI))];
document.body.style.position = 'absolute';
document.body.style.left = vals[0] + 'px';
document.body.style.top = vals[1] + 'px';
document.body.style.fontSize = vals[0] + 'px';
}
document.addEventListener('keydown', hideYourMind, false);

View file

@ -1,497 +0,0 @@
/*
* Sakura Yuuno
*/
declare var Sakura: any;
declare var AJAX: any;
declare var HTTPMethods: any;
declare var sakuraVars: any;
// Notification class
interface Notification {
read: boolean;
title: string;
text: string;
link: string;
image: string;
timeout: number;
}
// Spawns a notification
function notifyUI(content: Notification): void {
// Grab the container and create an ID
var cont: HTMLElement = document.getElementById('notifications');
var id: string = 'sakura-notification-' + Date.now();
// Create the elements
var alert: HTMLDivElement = document.createElement('div');
var aIcon: HTMLDivElement = document.createElement('div');
var aCont: HTMLDivElement = document.createElement('div');
var aTitle: HTMLDivElement = document.createElement('div');
var aText: HTMLDivElement = document.createElement('div');
var aClose: HTMLDivElement = document.createElement('div');
var aCIcon: HTMLDivElement = document.createElement('div');
var aClear: HTMLDivElement = document.createElement('div');
var aIconCont: any;
// Add attributes to the main element
alert.className = 'notification-enter';
alert.id = id;
// Add the icon
if ((typeof content.image).toLowerCase() === 'undefined' || content.image == null || content.image.length < 2) {
aIconCont = document.createElement('div');
aIconCont.className = 'font-icon fa fa-info fa-4x';
} else if (content.image.substr(0, 5) == 'FONT:') {
aIconCont = document.createElement('div');
aIconCont.className = 'font-icon fa ' + content.image.replace('FONT:', '') + ' fa-4x';
} else {
aIconCont = document.createElement('img');
aIconCont.alt = id;
aIconCont.src = content.image;
}
aIcon.appendChild(aIconCont);
aIcon.className = 'notification-icon';
alert.appendChild(aIcon);
// Add the content
aCont.className = 'notification-content';
aTitle.className = 'notification-title';
aText.className = 'notifcation-text';
aTitle.textContent = content.title;
aText.textContent = content.text;
// Check if a link exists and add if it does
if ((typeof content.link).toLowerCase() !== 'undefined' && content.link !== null && content.link.length > 1) {
alert.setAttribute('sakurahref', content.link);
aCont.setAttribute('onclick', content.link.substr(0, 11) == 'javascript:' ? content.link.substring(11) : 'notifyOpen(this.parentNode.id);');
}
// Append stuff
aCont.appendChild(aTitle);
aCont.appendChild(aText);
alert.appendChild(aCont);
// Add the close button
aClose.className = 'notification-close';
aClose.setAttribute('onclick', 'notifyClose(this.parentNode.id);');
aClose.appendChild(aCIcon);
alert.appendChild(aClose);
// Append the notification to the document
cont.appendChild(alert);
// If keepalive is 0 keep the notification open forever
if (content.timeout > 0) {
// Set a timeout and close after an amount
setTimeout(() => {
notifyClose(id);
}, content.timeout);
}
}
// Closing a notification
function notifyClose(id: string): void {
// Get the element
var e: HTMLElement = document.getElementById(id);
// Add the animation
e.className = 'notification-exit';
// Remove after 410 ms
setTimeout(() => {
(new Sakura.DOM(id, Sakura.DOMSelector.ID)).Remove();
}, 410);
}
// Opening an alerted link
function notifyOpen(id: string): void {
var sakuraHref: string = document.getElementById(id).getAttribute('sakurahref');
if ((typeof sakuraHref).toLowerCase() !== 'undefined') {
window.location.assign(sakuraHref);
}
}
// Show the full page busy window
function ajaxBusyView(show: boolean, message: string = null, type: string = null): void {
// Get elements
var cont: HTMLElement = document.getElementById('ajaxBusy');
var stat: HTMLElement = document.getElementById('ajaxStatus');
var anim: HTMLElement = document.getElementById('ajaxAnimate');
var body: HTMLElement = document.getElementById('contentwrapper');
var icon: string = 'fa fa-4x ';
// Select the proper icon
switch (type) {
case 'ok':
icon += 'fa-check';
break;
case 'fail':
icon += 'fa-remove';
break;
case 'busy':
default:
icon += 'fa-refresh fa-spin';
break;
}
// If request to show the window, build it
if (show) {
if ((typeof cont).toLowerCase() === 'undefined' || cont === null) {
// Container
var cCont = document.createElement('div');
cCont.className = 'ajax-busy';
cCont.id = 'ajaxBusy';
// Inner
var cInner = document.createElement('div');
cInner.className = 'ajax-inner';
cCont.appendChild(cInner);
// Desc
var cMsg = document.createElement('h2');
cMsg.id = 'ajaxStatus';
cInner.appendChild(cMsg);
// Icon
var cIco = document.createElement('div');
cIco.id = 'ajaxAnimate';
cInner.appendChild(cIco);
// Append to document
body.appendChild(cCont);
// Reassign
cont = document.getElementById('ajaxBusy');
stat = document.getElementById('ajaxStatus');
anim = document.getElementById('ajaxAnimate');
}
// Update the icon
anim.className = icon;
// Update the message
stat.textContent = (message === null ? '' : message);
} else {
if (cont !== null) {
var out: any = setInterval(() => {
if (cont.style.opacity === null || cont.style.opacity === "") {
cont.style.opacity = "1";
}
// If the value isn't 0 yet subtract by .1
if (parseInt(cont.style.opacity) > 0) {
cont.style.opacity = (parseInt(cont.style.opacity) - 0.1).toString();
} else {
(new Sakura.DOM('ajaxBusy', Sakura.DOMSelector.ID)).Remove();
clearInterval(out);
}
}, 10);
}
}
}
// Making a post request using AJAX
function ajaxPost(url: string, data: Object, callback: Function) {
// Create AJAX
var request = new Sakura.AJAX;
// Set url
request.SetUrl(url);
// Add callbacks
request.AddCallback(200, function() {
callback.call(request.Response())
});
request.AddCallback(0, function() {
ajaxBusyView(false);
throw "POST Request failed";
});
// Add header
request.AddHeader('Content-Type', 'application/x-www-form-urlencoded');
// Set the post data
request.SetSend(data);
// Make the request
request.Start(Sakura.HTTPMethod.POST);
// Return the AJAX object
return request;
}
// Convert a href attr to an object
function prepareAjaxLink(linkId: any, callback: Function, attrs: string = null): void {
// Get element
var link: HTMLElement = (typeof linkId).toLowerCase() === 'object' ? linkId : document.getElementById(linkId);
// Catch null
if (link === null) {
return;
}
// Get the raw HREF value
var href: string = link.getAttribute('href');
// Get the action
var action: string = href.split('?')[0];
// Split the request variables
var varEarly: string[] = href.split('?')[1].split('&');
// Create storage thing
var variables: Object = new Object();
// Split them
for (var k in varEarly) {
// Split
var newVar: string[] = varEarly[k].split('=');
// Push
variables[newVar[0]] = newVar[1];
}
// Add ajax=true
variables['ajax'] = true;
// Update link attributes
link.setAttribute('href', 'javascript:void(0);');
link.setAttribute('onclick', callback + '(\'' + action + '\', JSON.parse(\'' + JSON.stringify(variables) + '\')' + (typeof attrs != 'undefined' ? attrs : '') + ');');
}
// Prepare a form for an AJAX request
function prepareAjaxForm(formId: string, message: string, resetCaptcha: boolean = false): void {
// Get the form
var form: HTMLElement = document.getElementById(formId);
// Create hidden ajax input
var hide: HTMLInputElement = document.createElement('input');
// Set the attributes
hide.name = 'ajax';
hide.value = 'true';
hide.type = 'hidden';
form.appendChild(hide);
// Update form
form.setAttribute('onsubmit', 'submitPost(\'' + form.getAttribute('action') + '\', formToObject(\'' + formId + '\'), true, \'' + (message ? message : 'Please wait...') + '\', ' + (resetCaptcha ? 'true' : 'false') + ');');
form.setAttribute('action', 'javascript:void(0);');
}
// Convert form to an object
function formToObject(formId: string): Object {
// Get the form
var form: any = document.getElementById(formId);
// Make an object for the request parts
var requestParts: Object = new Object();
// Get all the children with a name attr
var children = form.querySelectorAll('[name]');
// Sort the children and make them ready for submission
for (var i in children) {
if ((typeof children[i]).toLowerCase() === 'object') {
requestParts[children[i].name] = ((typeof children[i].type !== "undefined" && children[i].type.toLowerCase() == "checkbox") ? (children[i].checked ? 1 : 0) : children[i].value);
}
}
// Return the request parts
return requestParts;
}
// Quickly building a form
function generateForm(formId: string, formAttr: Object, formData: Object, appendTo: string = null): HTMLFormElement {
// Create form element
var form: HTMLFormElement = document.createElement('form');
form.id = formId;
// Set additional attrs
for (var c in formAttr) {
form.setAttribute(c, formAttr[c]);
}
// Set data
for (var a in formData) {
var b: HTMLInputElement = document.createElement('input');
b.type = 'hidden';
b.name = a;
b.value = formData[a];
form.appendChild(b);
}
// Append to something if requested
if (appendTo !== null) {
document.getElementById(appendTo).appendChild(form);
}
return form;
}
// Submitting a post using AJAX
function submitPost(action: string, requestParts: Object, busyView: boolean, msg: string, resetCaptcha: boolean): void {
// If requested display the busy thing
if (busyView) {
ajaxBusyView(true, msg, 'busy');
}
// Submit the AJAX
var request = ajaxPost(action, requestParts, () => {
submitPostHandler(request.response(), busyView, resetCaptcha);
});
}
// Handling a submitted form using AJAX
function submitPostHandler(data: string, busyView: boolean, resetCaptcha: boolean): void {
// Split the result
var result: string[] = data.split('|');
// If using the bust view thing update the text displayed to the return of the request
if (busyView) {
ajaxBusyView(true, result[0], (result[1] == '1' ? 'ok' : 'fail'));
}
setTimeout(() => {
if (busyView) {
ajaxBusyView(false);
}
if (result[1] == '1') {
window.location.assign(result[2]);
}
}, 2000);
}
// Check if a password is within the minimum entropy value
function checkPwdEntropy(pwd: string): boolean {
return (Sakura.Legacy.entropy(pwd) >= sakuraVars.minPwdEntropy);
}
// Check registration variables
function registerVarCheck(id: string, mode: string, option: any = null): void {
// Get the element we're working with
var input: any = document.getElementById(id);
var check: boolean = null;
// Use the proper mode
switch (mode) {
case 'confirmpw':
option = document.getElementById(option);
check = input.value === option.value;
break;
case 'password':
check = checkPwdEntropy(input.value);
break;
case 'email':
check = Sakura.Legacy.validateEmail(input.value);
break;
case 'username':
default:
check = Sakura.Legacy.stringLength(input.value, sakuraVars.minUserLen, sakuraVars.maxUserLen);
break;
}
if (input.className.indexOf(check ? 'green' : 'red') < 0) {
input.className = input.className + ' ' + (check ? 'green' : 'red');
}
if (input.className.indexOf(check ? 'red' : 'green') > 0) {
input.className = input.className.replace(check ? 'red' : 'green', '');
}
}
// Replace some special tags
function replaceTag(tag: string): string {
return { '&': '&amp;', '<': '&lt;', '>': '&gt;' }[tag] || tag;
}
// ^
function safeTagsReplace(str: string): string {
return str.replace(/[&<>]/g, replaceTag);
}
// Inserting text into text box
// Borrowed from http://stackoverflow.com/questions/1064089/inserting-a-text-where-cursor-is-using-javascript-jquery (therefore not in Typescript format, fix this later)
function insertText(areaId, text) {
var txtarea: any = document.getElementById(areaId);
var scrollPos: any = txtarea.scrollTop;
var strPos = 0;
var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ?
"ff" : ((<any>document).selection ? "ie" : false));
if (br == "ie") {
txtarea.focus();
var range = (<any>document).selection.createRange();
range.moveStart('character', -txtarea.value.length);
strPos = range.text.length;
}
else if (br == "ff") strPos = txtarea.selectionStart;
var front = (txtarea.value).substring(0, strPos);
var back = (txtarea.value).substring(strPos, txtarea.value.length);
txtarea.value = front + text + back;
strPos = strPos + text.length;
if (br == "ie") {
txtarea.focus();
var range = (<any>document).selection.createRange();
range.moveStart('character', -txtarea.value.length);
range.moveStart('character', strPos);
range.moveEnd('character', 0);
range.select();
}
else if (br == "ff") {
txtarea.selectionStart = strPos;
txtarea.selectionEnd = strPos;
txtarea.focus();
}
txtarea.scrollTop = scrollPos;
}
// Inserting a bbcode
function insertBBcode(textarea: string, tag: string, arg: boolean = false): void {
var element: any = document.getElementById(textarea);
var before = "[" + tag + (arg ? "=" : "") + "]";
var after = "[/" + tag + "]";
if ((<any>document).selection) {
element.focus();
var sel = (<any>document).selection.createRange();
sel.text = before + sel.text + after;
element.focus();
} else if (element.selectionStart || element.selectionStart === 0) {
var startPos = element.selectionStart;
var endPos = element.selectionEnd;
var scrollTop = element.scrollTop;
element.value = element.value.substring(0, startPos) + before + element.value.substring(startPos, endPos) + after + element.value.substring(endPos, element.value.length);
element.focus();
element.selectionStart = startPos + before.length;
element.selectionEnd = endPos + before.length;
element.scrollTop = scrollTop;
} else {
element.value += before + after;
element.focus();
}
}
interface Number {
formatMoney(u, c, k);
}
// Formatting money
Number.prototype.formatMoney = function(u, c, k) {
var f = this,
u = isNaN(u = Math.abs(u)) ? 2 : u,
c = c == undefined ? "." : c,
k = k == undefined ? "," : k,
i = f < 0 ? "-" : "",
n: any = parseInt(f = Math.abs(+f || 0).toFixed(u)) + "",
g = (g = n.length) > 3 ? g % 3 : 0;
return i + (g ? n.substr(0, g) + k : "") + n.substr(g).replace(/(\c{3})(?=\c)/g, "$1" + k) + (u ? c + Math.abs(f - n).toFixed(u).slice(2) : "");
};

View file

@ -18,7 +18,7 @@
{#<script>
window["sakurakoSettings"] = route('chat.settings');
</script>#}
<script src="/js/libraries.js" data-turbolinks-track></script>
<!-- we'll disable turbolinks for now script src="/js/libraries.js" data-turbolinks-track></script-->
<script src="/js/aitemu.js" data-turbolinks-track></script>
{#<script src="{{ config('general.chat') }}/app.js"></script>#}
{{ block('js') }}
@ -29,7 +29,7 @@
<nav class="header">
<div class="header__navigation">
<a class="header__entry fa-home" href="{{ route('main.index') }}">home</a>
<a class="header__entry fa-comments" href="{{ forums.index }}">forum</a>
<a class="header__entry fa-comments" href="{{ route('forums.index') }}">forum</a>
<a class="header__entry fa-commenting" href="{{ route('chat.redirect') }}">chat</a>
<a class="header__entry fa-sign-out" href="{{ route('auth.logout') }}">logout</a>
</div>

View file

@ -1 +0,0 @@
# To make sure Git keeps this folder here

View file

@ -25,19 +25,19 @@
<label for="registerUserName">Username:</label>
</div>
<div class="centreAlign">
<input class="inputStyling" type="text" id="registerUserName" name="username" onkeyup="registerVarCheck(this.id, 'username');" placeholder="Any character"{% if get.username %} value="{{ get.username }}"{% endif %}>
<input class="inputStyling" type="text" id="registerUserName" name="username" placeholder="Any character"{% if get.username %} value="{{ get.username }}"{% endif %}>
</div>
<div class="leftAlign">
<label for="registerEmail">E-mail:</label>
</div>
<div class="centreAlign">
<input class="inputStyling" type="text" id="registerEmail" name="email" onkeyup="registerVarCheck(this.id, 'email');" placeholder="Used for e.g. password retrieval"{% if get.email %} value="{{ get.email }}"{% endif %}>
<input class="inputStyling" type="text" id="registerEmail" name="email" placeholder="Used for e.g. password retrieval"{% if get.email %} value="{{ get.email }}"{% endif %}>
</div>
<div class="leftAlign">
<label for="registerPassword">Password:</label>
</div>
<div class="centreAlign">
<input class="inputStyling" type="password" id="registerPassword" name="password" onkeyup="registerVarCheck(this.id, 'password');" placeholder="Using special characters is recommended">
<input class="inputStyling" type="password" id="registerPassword" name="password" placeholder="Using special characters is recommended">
</div>
<div class="centreAlign">
<input class="inputStyling" type="submit" name="submit" value="Register" id="registerAccBtn">

View file

@ -44,11 +44,7 @@
var resp = JSON.parse(commentClient.Response());
if (resp.error) {
ajaxBusyView(true, resp.error, 'fail');
setTimeout(function () {
ajaxBusyView(false);
}, 1500);
Yuuno.Busy.Show(Yuuno.BusyMode.FAIL, resp.error, 1500);
} else {
commentAdd(resp);
}
@ -197,7 +193,7 @@
// Remove it if it already exists
if (replyBox) {
(new Sakura.DOM('comment-reply-container-' + id, Sakura.DOMSelector.ID)).Remove();
Sakura.DOM.Remove('comment-reply-container-' + id);
return;
}
@ -256,13 +252,9 @@
var resp = JSON.parse(commentClient.Response());
if (resp.error) {
ajaxBusyView(true, resp.error, 'fail');
setTimeout(function () {
ajaxBusyView(false);
}, 1500);
Yuuno.Busy.Show(Yuuno.BusyMode.FAIL, resp.error, 1500);
} else {
(new Sakura.DOM("comment-" + id, Sakura.DOMSelector.ID)).Remove();
Sakura.DOM.Remove('comment-' + id);
}
});
@ -282,11 +274,7 @@
var resp = JSON.parse(commentClient.Response());
if (resp.error) {
ajaxBusyView(true, resp.error, 'fail');
setTimeout(function () {
ajaxBusyView(false);
}, 1500);
Yuuno.Busy.Show(Yuuno.BusyMode.FAIL, resp.error, 1500);
} else {
upvotes.innerText = resp.upvotes;
downvotes.innerText = resp.downvotes;

View file

@ -24,7 +24,7 @@
<div class="posting-buttons">
<div style="float: left;">
{% for code,meta in bbcode %}
<button onclick="insertBBcode('postingText', '{{ code }}'{% if meta[2] %}, true{% endif %});" type="button"{% if meta[0] %} title="{{ meta[0] }}"{% endif %} class="forumbtn{% if meta[1] %} fa fa-{{ meta[1] }}{% endif %}">{% if not meta[1] %}{{ code }}{% endif %}</button>
<button onclick="Yuuno.Editor.InsertBBCode(Sakura.DOM.ID('postingText'), '{{ code }}'{% if meta[2] %}, true{% endif %});" type="button"{% if meta[0] %} title="{{ meta[0] }}"{% endif %} class="forumbtn{% if meta[1] %} fa fa-{{ meta[1] }}{% endif %}">{% if not meta[1] %}{{ code }}{% endif %}</button>
{% endfor %}
</div>
<div style="float: right;">

View file

@ -18,37 +18,17 @@
<script type="text/javascript" src="/js/app.js"></script>
<script type="text/javascript" src="/js/yuuno.js"></script>
<script type="text/javascript">
// Create an object so we can access certain settings from remote JavaScript files
var sakuraVars = {
"cookie": {
"prefix": "{{ config('cookie.prefix') }}"
},
"siteName": "{{ config('general.name') }}",
"content": "",
"recaptchaEnabled": false,
"minUserLen": {{ config('user.name_min') }},
"maxUserLen": {{ config('user.name_max') }},
"minPwdEntropy": {{ config('user.pass_min_entropy') }},
"checkLogin": {{ user.isActive ? 'true' : 'false' }}
};
// Error reporter
window.onerror = function(msg, url, line, col, error) {
notifyUI({
"title": "An error has occurred!",
"text": "There was a problem while executing the JavaScript code for this page: " + msg + ", URL: " + url + ", Line: " + line + ", Column: " + col + ". Please report this to a developer.",
"image": "FONT:fa-warning"
});
}
</script>
{{ block('js') }}
</head>
<body>
<div id="container">
<span id="top"></span>
<div id="busy-window" class="ajax-busy hidden">
<div class="ajax-inner">
<h2 id="busy-status"></h2>
<div class="fa fa-4x fa-refresh fa-spin" id="busy-icon"></div>
</div>
</div>
<div class="header" id="header">
<a class="logo" href="{{ route('main.index') }}">{% if config('general.logo') %}<img src="{{ config('general.logo') }}" alt="{{ config('general.name') }}">{% else %}{{ config('general.name') }}{% endif %}</a>
<div class="menu fa">
@ -154,7 +134,7 @@
<li class="fthead">Information</li>
<li><a href="{{ route('main.faq') }}">FAQ</a></li>
<li><a href="{{ route('info.rules') }}">Rules</a></li>
<li><a href="//fiistat.us" target="_blank">Server Status</a></li>
<li><a href="{{ route('status.index') }}">Server Status</a></li>
<li><a href="{{ route('info.terms') }}">Terms of Service</a></li>
</ul>
</div>
@ -163,9 +143,6 @@
<script type="text/javascript">
Sakura.Config.Set({
Revision: {{ constant('SAKURA_VERSION') }},
UserNameMinLength: {{ config('user.name_min') }},
UserNameMaxLength: {{ config('user.name_max') }},
PasswordMinEntropy: {{ config('user.pass_min_entropy') }},
LoggedIn: {{ user.isActive ? 'true' : 'false' }},
UserId: {{ user.id }},
SessionId: "{{ session_id() }}",
@ -173,8 +150,20 @@
Yuuno.Main.Startup();
{% if config('dev.show_changelog', true) and stats %}
Sakura.Changelog.Build(new Sakura.DOM('indexPanel', Sakura.DOMSelector.ID));
{% if config('dev.show_changelog') and stats %}
Sakura.Changelog.Build(Sakura.DOM.ID('indexPanel'));
{% endif %}
{% if config('dev.show_errors') %}
window.addEventListener("error", function () {
Yuuno.Notifications.Display({
id: -(Date.now()),
title: "Something happened!",
text: "Check the console for more info.",
image: "FONT:fa-bomb",
link: null,
});
});
{% endif %}
</script>
</body>

View file

@ -14,7 +14,3 @@
<div class="clear"></div>
</div>
{% endblock %}
{% block js %}
<script type="text/javascript" src="/js/ybabstat.js"></script>
{% endblock %}

View file

@ -68,14 +68,14 @@
</div>
{% if user.isActive and user.permission(constant('Sakura\\Perms\\Site::OBTAIN_PREMIUM')) %}
<div class="slider">
<input class="inputStyling" type="range" min="1" max="{{ amountLimit }}" value="1" onchange="document.getElementById('monthsNo').value = this.value; document.getElementById('monthNoBtn').innerHTML = this.value; document.getElementById('monthsTrailingS').innerHTML = (this.value == 1 ? '' : 's'); document.getElementById('totalAmount').innerHTML = (this.value * {{ price }}).formatMoney(2);">
<input class="inputStyling" type="range" min="1" max="{{ amountLimit }}" value="1" onchange="document.getElementById('monthsNo').value = this.value; document.getElementById('monthNoBtn').innerText = this.value; document.getElementById('monthsTrailingS').innerText = (this.value == 1 ? '' : 's'); document.getElementById('totalAmount').innerText = (this.value * {{ price }});">
</div>
<div class="checkout" style="line-height: 28px;">
<div style="float: left;">
<h1 class="stylised">Total: &#8364;<span id="totalAmount"></span></h1>
</div>
<div style="float: right;">
<button class="inputStyling" onclick="ajaxBusyView(true, 'Please wait...');document.getElementById('purchaseForm').submit();">Get <span id="monthNoBtn">1</span> month<span id="monthsTrailingS"></span> of Tenshi</button>
<button class="inputStyling" onclick="Yuuno.Busy.Show(Yuuno.BusyMode.BUSY, 'Please wait...');document.getElementById('purchaseForm').submit();">Get <span id="monthNoBtn">1</span> month<span id="monthsTrailingS"></span> of Tenshi</button>
</div>
<div class="clear"></div>
</div>
@ -93,7 +93,7 @@
<input type="hidden" name="months" id="monthsNo" value="1">
</form>
<script type="text/javascript">
window.onload = function() { document.getElementById('totalAmount').innerHTML = ({{ price }}).formatMoney(2); };
window.onload = function() { document.getElementById('totalAmount').innerText = {{ price }}; };
</script>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,16 @@
{% extends '@aitemu/master.twig' %}
{% set title = 'Status' %}
{% set banner = '/images/status-banner.png' %}
{% set banner_large = true %}
{% block banner_content %}
{# ignore this, it's temporary #}
<div style="display:flex;width:100%;height:100%;"><div class="fa-4x" style="align-self:center;padding:1em"><span class="fa fa-check"></span> I can write in here too!</div></div>
{% endblock %}
{% block content %}
<div class="platform">
all services are operational and i haven't designed this yet
</div>
{% endblock %}

View file

@ -104,6 +104,11 @@ Router::group(['before' => 'maintenance'], function () {
Router::get('/welcome', 'InfoController@welcome', 'info.welcome');
});
// Status
Router::group(['prefix' => 'status'], function () {
Router::get('/', 'StatusController@index', 'status.index');
});
// News
Router::group(['prefix' => 'news'], function () {
Router::get('/{category:c}?', 'NewsController@category', 'news.category');

View file

@ -7,7 +7,7 @@
namespace Sakura;
// Define version and root path
define('SAKURA_VERSION', 20160730);
define('SAKURA_VERSION', 20160804);
define('ROOT', __DIR__ . '/');
// CLI mode

View file

@ -4,7 +4,6 @@
"noImplicitAny": false,
"removeComments": true,
"preserveConstEnums": true,
"moduleResolution": "node",
"rootDir": "resources/assets/typescript"
}
}