making a lot of progress on the js side
This commit is contained in:
parent
3d8c30e8b6
commit
deecbbaf0f
33 changed files with 533 additions and 826 deletions
22
app/Controllers/StatusController.php
Normal file
22
app/Controllers/StatusController.php
Normal 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');
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
|
BIN
public/images/status-banner.png
Normal file
BIN
public/images/status-banner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 487 KiB |
17
resources/assets/typescript/Sakura.ts
Normal file
17
resources/assets/typescript/Sakura.ts
Normal 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" />
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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/";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
namespace Sakura
|
||||
{
|
||||
export enum DOMSelector
|
||||
{
|
||||
ID,
|
||||
CLASS,
|
||||
ELEMENT,
|
||||
QUERY
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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') {
|
||||
|
|
6
resources/assets/typescript/Yuuno.ts
Normal file
6
resources/assets/typescript/Yuuno.ts
Normal 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" />
|
47
resources/assets/typescript/Yuuno/Busy.ts
Normal file
47
resources/assets/typescript/Yuuno/Busy.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
resources/assets/typescript/Yuuno/BusyMode.ts
Normal file
9
resources/assets/typescript/Yuuno/BusyMode.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Yuuno
|
||||
{
|
||||
export enum BusyMode
|
||||
{
|
||||
OK,
|
||||
FAIL,
|
||||
BUSY
|
||||
}
|
||||
}
|
20
resources/assets/typescript/Yuuno/Editor.ts
Normal file
20
resources/assets/typescript/Yuuno/Editor.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 { '&': '&', '<': '<', '>': '>' }[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) : "");
|
||||
};
|
|
@ -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>
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
# To make sure Git keeps this folder here
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -14,7 +14,3 @@
|
|||
<div class="clear"></div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/ybabstat.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -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: €<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 %}
|
||||
|
|
16
resources/views/yuuno/status/index.twig
Normal file
16
resources/views/yuuno/status/index.twig
Normal 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 %}
|
|
@ -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');
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
namespace Sakura;
|
||||
|
||||
// Define version and root path
|
||||
define('SAKURA_VERSION', 20160730);
|
||||
define('SAKURA_VERSION', 20160804);
|
||||
define('ROOT', __DIR__ . '/');
|
||||
|
||||
// CLI mode
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"preserveConstEnums": true,
|
||||
"moduleResolution": "node",
|
||||
"rootDir": "resources/assets/typescript"
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue