diff --git a/app/Controllers/StatusController.php b/app/Controllers/StatusController.php
new file mode 100644
index 0000000..871ae51
--- /dev/null
+++ b/app/Controllers/StatusController.php
@@ -0,0 +1,22 @@
+
+ */
+class StatusController extends Controller
+{
+ public function index()
+ {
+ return view('status/index');
+ }
+}
diff --git a/app/Template.php b/app/Template.php
index 68a383b..8e2b023 100644
--- a/app/Template.php
+++ b/app/Template.php
@@ -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());
diff --git a/public/images/status-banner.png b/public/images/status-banner.png
new file mode 100644
index 0000000..3064da6
Binary files /dev/null and b/public/images/status-banner.png differ
diff --git a/resources/assets/typescript/Sakura.ts b/resources/assets/typescript/Sakura.ts
new file mode 100644
index 0000000..c9ceeed
--- /dev/null
+++ b/resources/assets/typescript/Sakura.ts
@@ -0,0 +1,17 @@
+///
+///
+///
+///
+///
+///
+///
+///
+///
+///
+///
+///
+///
+///
+///
+///
+///
diff --git a/resources/assets/typescript/Sakura/Changelog.ts b/resources/assets/typescript/Sakura/Changelog.ts
index c60978d..c8a90ee 100644
--- a/resources/assets/typescript/Sakura/Changelog.ts
+++ b/resources/assets/typescript/Sakura/Changelog.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 = 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 = DOM.Create('div', 'head'),
+ link: HTMLLinkElement = DOM.Create('a', 'underline');
- title.Element.style.marginBottom = '1px';
+ title.style.marginBottom = '1px';
- link.Text('Changelog');
- (link.Element).href = Config.ChangelogUrl + '#r' + Config.Revision;
- (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 = DOM.Create('tr', 'changelog__row changelog__row--header'),
+ headerInner: HTMLTableHeaderCellElement = DOM.Create('th', 'changelog__header');
- headerInner.Text(changelog.date);
- headerInner.Element.style.fontSize = '1.2em';
- (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 = DOM.Create('tr', 'changelog__row'),
+ action: HTMLTableCellElement = DOM.Create('td', 'changelog__column'),
+ message: 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);
}
}
}
diff --git a/resources/assets/typescript/Sakura/Config.ts b/resources/assets/typescript/Sakura/Config.ts
index c46f610..93396fe 100644
--- a/resources/assets/typescript/Sakura/Config.ts
+++ b/resources/assets/typescript/Sakura/Config.ts
@@ -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/";
diff --git a/resources/assets/typescript/Sakura/DOM.ts b/resources/assets/typescript/Sakura/DOM.ts
index 4f1c645..bab1980 100644
--- a/resources/assets/typescript/Sakura/DOM.ts
+++ b/resources/assets/typescript/Sakura/DOM.ts
@@ -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 = document.getElementsByClassName(object)[0];
- break;
-
- case DOMSelector.ELEMENT:
- this.Element = object;
- break;
-
- case DOMSelector.QUERY:
- this.Element = 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 {
+ return >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 (subject.cloneNode(true));
+ }
+
+ public static Query(query: string): NodeListOf {
+ 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;
}
}
}
diff --git a/resources/assets/typescript/Sakura/DOMSelector.ts b/resources/assets/typescript/Sakura/DOMSelector.ts
deleted file mode 100644
index 6829598..0000000
--- a/resources/assets/typescript/Sakura/DOMSelector.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace Sakura
-{
- export enum DOMSelector
- {
- ID,
- CLASS,
- ELEMENT,
- QUERY
- }
-}
diff --git a/resources/assets/typescript/Sakura/Friend.ts b/resources/assets/typescript/Sakura/Friend.ts
index 3ed7651..a0671df 100644
--- a/resources/assets/typescript/Sakura/Friend.ts
+++ b/resources/assets/typescript/Sakura/Friend.ts
@@ -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 = 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);
}
diff --git a/resources/assets/typescript/Sakura/Legacy.ts b/resources/assets/typescript/Sakura/Legacy.ts
deleted file mode 100644
index 3ee288f..0000000
--- a/resources/assets/typescript/Sakura/Legacy.ts
+++ /dev/null
@@ -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));
- }
- }
-}
diff --git a/resources/assets/typescript/Sakura/Main.ts b/resources/assets/typescript/Sakura/Main.ts
deleted file mode 100644
index bc3fb17..0000000
--- a/resources/assets/typescript/Sakura/Main.ts
+++ /dev/null
@@ -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;
- }
- }
-}
diff --git a/resources/assets/typescript/Sakura/Notifications.ts b/resources/assets/typescript/Sakura/Notifications.ts
index bf8bd34..13548f1 100644
--- a/resources/assets/typescript/Sakura/Notifications.ts
+++ b/resources/assets/typescript/Sakura/Notifications.ts
@@ -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(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);
+ }
}
}
diff --git a/resources/assets/typescript/Sakura/TimeAgo.ts b/resources/assets/typescript/Sakura/TimeAgo.ts
index 1441e90..6e0e685 100644
--- a/resources/assets/typescript/Sakura/TimeAgo.ts
+++ b/resources/assets/typescript/Sakura/TimeAgo.ts
@@ -6,7 +6,7 @@ namespace Sakura
public static Init(): void
{
- var watchElements: NodeListOf = document.getElementsByClassName(this.WatchClass);
+ var watchElements: NodeListOf = DOM.Class(this.WatchClass);
for (var _i in watchElements) {
if ((typeof watchElements[_i]).toLowerCase() !== 'object') {
diff --git a/resources/assets/typescript/Yuuno.ts b/resources/assets/typescript/Yuuno.ts
new file mode 100644
index 0000000..e693123
--- /dev/null
+++ b/resources/assets/typescript/Yuuno.ts
@@ -0,0 +1,6 @@
+///
+///
+///
+///
+///
+///
diff --git a/resources/assets/typescript/Yuuno/Busy.ts b/resources/assets/typescript/Yuuno/Busy.ts
new file mode 100644
index 0000000..0f71c9c
--- /dev/null
+++ b/resources/assets/typescript/Yuuno/Busy.ts
@@ -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);
+ }
+ }
+ }
+}
diff --git a/resources/assets/typescript/Yuuno/BusyMode.ts b/resources/assets/typescript/Yuuno/BusyMode.ts
new file mode 100644
index 0000000..bf28d17
--- /dev/null
+++ b/resources/assets/typescript/Yuuno/BusyMode.ts
@@ -0,0 +1,9 @@
+namespace Yuuno
+{
+ export enum BusyMode
+ {
+ OK,
+ FAIL,
+ BUSY
+ }
+}
diff --git a/resources/assets/typescript/Yuuno/Editor.ts b/resources/assets/typescript/Yuuno/Editor.ts
new file mode 100644
index 0000000..4e71c2e
--- /dev/null
+++ b/resources/assets/typescript/Yuuno/Editor.ts
@@ -0,0 +1,20 @@
+///
+
+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);
+ }
+ }
+}
diff --git a/resources/assets/typescript/Yuuno/Notifications.ts b/resources/assets/typescript/Yuuno/Notifications.ts
index 98f8e00..07027b9 100644
--- a/resources/assets/typescript/Yuuno/Notifications.ts
+++ b/resources/assets/typescript/Yuuno/Notifications.ts
@@ -1,28 +1,75 @@
-///
+///
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 = Sakura.DOM.Create('div', 'notification-enter', id),
+ iconContent: HTMLDivElement = Sakura.DOM.Create('div'),
+ icon: HTMLDivElement = Sakura.DOM.Create('div', 'notification-icon'),
+ inner: HTMLDivElement = Sakura.DOM.Create('div', 'notification-content'),
+ title: HTMLDivElement = Sakura.DOM.Create('div', 'notification-title'),
+ text: HTMLDivElement = Sakura.DOM.Create('div', 'notification-text'),
+ close: HTMLDivElement = Sakura.DOM.Create('div', 'notification-close'),
+ closeIcon: 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);
}
}
}
diff --git a/resources/assets/typescript/yuuno/Main.ts b/resources/assets/typescript/yuuno/Main.ts
index fadd7b5..fa9629c 100644
--- a/resources/assets/typescript/yuuno/Main.ts
+++ b/resources/assets/typescript/yuuno/Main.ts
@@ -1,11 +1,19 @@
+///
+
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();
+ }
}
}
}
diff --git a/resources/assets/typescript/yuuno/ybabstat.ts b/resources/assets/typescript/yuuno/ybabstat.ts
index a9c36c7..503d860 100644
--- a/resources/assets/typescript/yuuno/ybabstat.ts
+++ b/resources/assets/typescript/yuuno/ybabstat.ts
@@ -1,68 +1,82 @@
-var illuminati: Array = new Array();
-var startTime: number = (new Date()).getTime();
+///
-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 = Sakura.DOM.Create('audio'),
+ friendsWhenThey: HTMLSourceElement = Sakura.DOM.Create('source'),
+ comeToMyHouse: HTMLSourceElement = Sakura.DOM.Create('source');
- toMyHouse.play();
+ friendsWhenThey.type = 'audio/mp3';
+ comeToMyHouse.type = 'audio/ogg';
- illuminati = new Array();
- }
+ 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 = Sakura.DOM.Create('audio'),
+ von: HTMLSourceElement = Sakura.DOM.Create('source'),
+ schnitzel: 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();
- }
+ 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();
+ 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 = [-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);
diff --git a/resources/assets/typescript/yuuno/yuuno.ts b/resources/assets/typescript/yuuno/yuuno.ts
deleted file mode 100644
index 0d35999..0000000
--- a/resources/assets/typescript/yuuno/yuuno.ts
+++ /dev/null
@@ -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" : ((document).selection ? "ie" : false));
- if (br == "ie") {
- txtarea.focus();
- var range = (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 = (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 ((document).selection) {
- element.focus();
- var sel = (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) : "");
-};
diff --git a/resources/views/aitemu/master.twig b/resources/views/aitemu/master.twig
index f539aac..fec031a 100644
--- a/resources/views/aitemu/master.twig
+++ b/resources/views/aitemu/master.twig
@@ -18,7 +18,7 @@
{##}
-
+
{##}
{{ block('js') }}
@@ -29,7 +29,7 @@