Browse Source

junk: Clean code add logging

This commit adds Logger class for JavaScript.
It helps to logging errors to console and variables (can be easly turned off).
Cleaning code - all TypeScript files was cleaned, code was corrected.
Added comments and comment header for files in which it was missing.
Rewrite concept for catching elements in filemanager - now it operaters on data attributes, not on ID.
Cleaned filemanager index view.
Corrected css classes.

Issue: #43
master
Kamil Biały 2 years ago
parent
commit
d96b47ed5f
17 changed files with 1488 additions and 547 deletions
  1. +36
    -18
      public/themes/pluto/css/admin.css
  2. +85
    -11
      public/themes/pluto/src.static/Application.ts
  3. +88
    -0
      public/themes/pluto/src.static/Logger.ts
  4. +133
    -0
      public/themes/pluto/src.static/Prototypes.ts
  5. +15
    -8
      public/themes/pluto/src.static/controls/CheckBox.ts
  6. +354
    -392
      public/themes/pluto/src.static/controls/FileManager.ts
  7. +85
    -37
      public/themes/pluto/src.static/controls/TabControl.ts
  8. +28
    -2
      public/themes/pluto/src.static/extra/ObservableArray.ts
  9. +34
    -2
      public/themes/pluto/src.static/extra/RenderArray.ts
  10. +60
    -2
      public/themes/pluto/src.static/extra/RenderArrayTree.ts
  11. +96
    -2
      public/themes/pluto/src.static/interfaces/IEntity.ts
  12. +205
    -26
      public/themes/pluto/src.static/interfaces/IFileManager.ts
  13. +66
    -0
      public/themes/pluto/src.static/interfaces/IObservable.ts
  14. +111
    -0
      public/themes/pluto/src.static/interfaces/IRender.ts
  15. +2
    -1
      public/themes/pluto/src.static/tsconfig.json
  16. +88
    -45
      pulsar/admin/views/pluto/filemanager/index.volt
  17. +2
    -1
      tsconfig.static.json

+ 36
- 18
public/themes/pluto/css/admin.css View File

@@ -988,25 +988,25 @@ form .button-container {
width: 70% !important;
}

.filemanager .sidebar {
#filemanager aside {
width: 30%;
max-width: 350px;
min-width: 200px;
border-right: 1px #ccc solid;
}
.filemanager .breadcrumb {
#filemanager .breadcrumb {
border-color: #ccc;
padding: 0;
}
.filemanager .breadcrumb .title {
#filemanager .breadcrumb .title {
margin-left: 1rem;
color: #127889;
}
.filemanager .breadcrumb .title.root {
#filemanager .breadcrumb .title.root {
color: #c83737;
}

.filemanager .caret {
#filemanager .caret {
width: 2.0rem;
text-align: center;
font-size: 1.4rem;
@@ -1115,10 +1115,10 @@ form .button-container {
content: "\f115";
}

.filemanager .dir-entry span, .filemanager .entity-entry span {
#filemanager .dir-entry span, #filemanager .entity-entry span {
line-height: 2rem;
}
.filemanager .dir-entry, .filemanager .entity-entry {
#filemanager .dir-entry, #filemanager .entity-entry {
list-style: none;
margin-left: 0;
user-select: none;
@@ -1157,33 +1157,33 @@ li.entity-entry.selected:hover i {
line-height: 3rem;
}

#FM_E-Details {
.entity-panel .details {
text-align: center;
min-height: 100%;
align-items: stretch;
}
.img-details-container {
.details-container {
display: flex;
flex: 1 1 0;
}
#FM_E-FileInfo {
.entity-panel .file-info {
border-top: 0.1rem #ccc solid;
padding-top: 0.5rem;
}
#FM_E-FileInfo dt {
.entity-panel .file-info dt {
width: 50%;
float: left;
font-weight: bold;
padding-right: 0.5rem;
text-align: right;
}
#FM_E-FileInfo dd {
.entity-panel .file-info dd {
width: 50%;
float: left;
text-align: left;
}

#FM_E-ImgPreview {
.details-container img {
max-width: 100%;
max-height: 100%;
object-fit: scale-down;
@@ -1191,25 +1191,25 @@ li.entity-entry.selected:hover i {
flex: 1 1 0;
padding-bottom: 0.5rem;
}
#FM_E-FilePreview {
.details-container textarea {
width: 100%;
resize: none;
margin-bottom: 0.5rem;
}
#FM_E-FilePreview:focus {
.details-container textarea:focus {
outline: none;
}
#FM_E-FolderName, #FM_E-FileList {
#filemanager input[type="text"] {
border: 0;
border-left: 1px #ccc solid;
border-right: 1px #ccc solid;
background: #fff;
}
#FM_E-FolderName:focus, #FM_E-FileList:focus {
#filemanager input[type="text"]:focus {
outline: none;
box-shadow: none;
}
#FM_E-FileUpload input[type="file"] {
#filemanager input[type="file"] {
width: 0;
height: 0;
opacity: 0;
@@ -1220,3 +1220,21 @@ li.entity-entry.selected:hover i {
.breadcrumb .button.simple {
line-height: 3rem;
}

.popup {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.popup.light {
background: rgba(192, 192, 192, 0.5);
}
.popup .container {
background: #fff;
}
.popup.light .container {
border: 1px #bbb solid;
margin: auto;
}

+ 85
- 11
public/themes/pluto/src.static/Application.ts View File

@@ -13,6 +13,9 @@
* this program. If not, see <http://www.licenses.aculo.pl/>.
*/

// =============================================================================

// wyrażenia regularne używane przy parsowaniu szablonów w bibliotece doT
const doTRegex = [
/\<\%([\s\S]+?)\%\>/g,
/\<\%=([\s\S]+?)\%\>/g,
@@ -23,6 +26,18 @@ const doTRegex = [
/\<\%~\s*(?:\%\>|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\%\>)/g
];

// =============================================================================

/**
* Klasa główna aplikacji.
*
* DESCRIPTION:
* Inicjalizuje elementy które wymagają obsługi JavaScript do działania.
* Są to między innymi: kontrolki zakładek, przyciski zaznaczania czy
* menedżer plików.
* Wszystkie z nich są inicjalizowane w odpowiednich funkcjach umieszczonych
* w tej klasie.
*/
class Application
{
/**
@@ -50,17 +65,26 @@ class Application
*/
public initTabControls(): void
{
$$<HTMLElement>( ".tab-control" ).forEach( elem =>
{
if( !elem.dataset.search )
return;
const tabs = $$<HTMLElement>(".tab-control");
if( !tabs || tabs.length == 0 )
return;

Logger.Debug(
"init",
`Creating tab controls, total: ${tabs.length}`
);
tabs.forEach( elem =>
{
const tab = new TabControl( elem );

if( !tab )
return;

// sprawdź która zakładka jest zaznaczona
const selected = tab.get("tabs").findIndex( (elem: any) => {
return elem.classList.contains( "selected" );
} );
const selected = tab.get("tabs").findIndex( (elem: any) =>
elem.classList.contains("selected")
);

tab.selectTab( selected, true );
} );
@@ -71,20 +95,46 @@ class Application
*/
public initCheckBoxes(): void
{
$$<HTMLElement>( ".checkbox" ).forEach( elem => new CheckBox(elem) );
const checkboxes = $$<HTMLElement>(".checkbox");

if( !checkboxes || checkboxes.length == 0 )
return;

Logger.Debug(
"init",
`Creating checkboxes, total: ${checkboxes.length}`
);
checkboxes.forEach( elem => new CheckBox(elem) );
}

/**
* Podpina akcje pod znaleziony element menedżera plików.
*
* DESCRIPTION:
* Menedżer plików powinien być tylko jeden.
* Po inicjalizacji powinien być odpowiednio podpinany w miejsce gdzie
* użytkownik chce móc wybierać pliki lub je przeglądać i wgrywać.
* Szczegóły dotyczące inicjalizacji menedżera plików znajdują się
* w klasie FileManager.
*/
public initFileManager(): void
{
const fmgrdiv = $<HTMLElement>( ".filemanager" );
const fmgrdiv = $<HTMLElement>("#filemanager");

if( !fmgrdiv )
return;

new FileManager( fmgrdiv );
Logger.Debug( "init", "Creating filemanager instance" );

new FileManager( {
element: fmgrdiv,
treeSelector: ".directory-subtree",
childIndex: "children",
actionClasses: {
showSidebar: "fa-arrow-circle-o-left",
hideSidebar: "fa-arrow-circle-o-right"
}
} );
}

/**
@@ -100,15 +150,38 @@ class Application
*/
public initConfirmMessages(): void
{
$$<HTMLElement>( ".show-confirm" ).forEach( elem =>
const messages = $$<HTMLElement>(".show-confirm");

if( !messages || messages.length == 0 )
return;

Logger.Debug(
"init",
`Initializing confirms, total: ${messages.length}`
);

messages.forEach( elem =>
{
// znacznik musi posiadać atrybut zawierający wyświetlaną wiadomość
if( !("confirm" in elem.dataset) )
{
Logger.Warning(
"init",
"Missing 'data-confirm' attribute in confirm"
);
return;
}

// akcja wywoływana po kliknięciu w element
elem.addEventListener( "click", (ev: MouseEvent) =>
{
if( confirm(elem.dataset.confirm) )
{
Logger.Info( "confirm", "Question was accepted" );
return true;
}

Logger.Info( "confirm", "Question was rejected" );

ev.stopPropagation();
ev.preventDefault();
@@ -120,6 +193,7 @@ class Application

// =============================================================================

// przygotuj aplikacje do działania dopiero po załadowaniu całego dokumentu
document.addEventListener( "DOMContentLoaded", () =>
{
const app = new Application();

+ 88
- 0
public/themes/pluto/src.static/Logger.ts View File

@@ -0,0 +1,88 @@
/*
* This file is part of Pulsar CMS
* Copyright (c) by sobiemir <sobiemir@aculo.pl>
* ___ __
* / _ \__ __/ /__ ___ _____
* / ___/ // / (_-</ _ `/ __/
* /_/ \_,_/_/___/\_,_/_/
*
* This source file is subject to the New BSD License that is bundled
* with this package in the file LICENSE.txt.
*
* You should have received a copy of the New BSD License along with
* this program. If not, see <http://www.licenses.aculo.pl/>.
*/

// =============================================================================

class Logger
{
private static _debugs: string[] = [];
private static _infos: string[] = [];
private static _warnings: string[] = [];
private static _errors: string[] = [];

private static _messages = {
NoAttrElem: "Missing element defined in '{0}' attribute",
NoIndex: "Object doesn't have index with name '{0}'",
NoElem: "Element with selector '{0}' doesn't exist in current content"
};

// -----------------------------------------------------------------------------

public static Debug( category: string, message: string ): boolean
{
message = `[${category}]: ${message}.`;

this._debugs.push( message );
console.log( message );

return true;
}

public static Info( category: string, message: string ): boolean
{
message = `[${category}]: ${message}.`;

this._infos.push( message );
console.info( message );

return true;
}

public static Warning( category: string, message: string ): boolean
{
message = `[${category}]: ${message}.`;

this._warnings.push( message );
console.warn( message );

return true;
}

public static Error( category: string, message: string ): boolean
{
message = `[${category}]: ${message}.`;

this._errors.push( message );
console.error( message );

return true;
}

public static $( category: string, index: string, ...args: any[] ): boolean
{
if( !(index in this._messages) )
this.Error(
"log",
`Cannot find static message with index '${index}'`
);
else
this.Warning(
category,
(<string>(<any>this._messages)[index]).formatArgs(args)
);

return true;
}
}

+ 133
- 0
public/themes/pluto/src.static/Prototypes.ts View File

@@ -29,6 +29,8 @@ interface NodeList
findIndex( func: (elem: any) => boolean ): number;
}

// =============================================================================

interface Array<T>
{
/**
@@ -42,6 +44,38 @@ interface Array<T>
deepSort( func: (a: T, b: T) => number, index: string ): void;
}

// =============================================================================

interface Number
{
/**
* Skraca liczbę do najlepszej i najbliższej wykrytej jednostki.
*
* DESCRIPTION:
* Skrócona liczba będzie zakończona wartością reprezentującą jednostkę.
* Liczba początkowa od której rozpoczynać się będzie skracanie
* traktowana jest jako liczba bajtów.
*
* RETURNS: string
* Zamienioną do najlepszej jednostki liczbę.
*/
toSizeString(): string;

/**
* Formatuje liczbę na datę, traktując ją jako znacznik czasowy.
*
* DESCRIPTION:
* Znacznik czasu rozpoczyna datę od 1 stycznia 1970 roku.
* Wyjściowy format daty jest zawsze taki sam: HH:mm - dd/MM/yyyy.
*
* RETURNS: string
* Data utworzona ze znacznika czasowego.
*/
toDateString(): string;
}

// =============================================================================

interface Element
{
/**
@@ -63,6 +97,25 @@ interface Element
$$<T extends Element = Element>( selector: string ): NodeListOf<T>;
}

// =============================================================================

interface String
{
/**
* Formatuje ciąg znaków używając podanych argumentów.
*
* PARAMETERS:
* args: any[]
* Argumenty formatowane w ciągu.
*
* RETURNS: string
* Ciąg wyjściowy.
*/
formatArgs( args: any[] ): string;
}

// =============================================================================

interface Document
{
/**
@@ -84,6 +137,8 @@ interface Document
$$<T extends Element = Element>( selector: string ): NodeListOf<T>;
}

// =============================================================================

/**
* Skrót funkcji querySelector pozwalający na bezpośrednie rzutowanie.
*
@@ -104,6 +159,25 @@ declare var $:
declare var $$:
<T extends Element = Element>( selector: string ) => NodeListOf<T>;

/**
* Uzupełnia obiekt względem kluczy w elementach przekazywanego obiektu.
*
* DESCRIPTION:
* Pozwala na uzupełnienie obiektu wartościami z przekazanego obiektu.
* Obiektem wynikowym będzie obiekt z kluczami przekazanego obiektu.
* Aby wszystko działało, obiekt musi być uprzednio zainicjalizowany.
*
* EXAMPLE:
* elems = $("[data-panels]");
* obj.fillByKey( elems, "dataset", "panel" );
*
* PARAMETERS:
* o Obiekt którym wartości będą uzupełniane.
* k1 Pierwszy klucz sprawdzania indeksu.
* k2 Drugi klucz sprawdzania indeksu (opcjonalny).
*/
declare var $fill: ( o1: any, o2: any, k1: string, k2?: string ) => void;

// =============================================================================

$ = function<T extends Element>( selector: string ): T
@@ -116,6 +190,21 @@ $$ = function<T extends Element = Element>( selector: string ): NodeListOf<T>
return <NodeListOf<T>>document.querySelectorAll( selector );
};

$fill = function( o1: any, o2: any, k1: string, k2?: string ): void
{
if( k2 && k1 )
{
for( const elem of o2 )
if( elem[k1][k2] in o1 )
o1[elem[k1][k2]] = elem;
return;
}

for( const elem of o2 )
if( elem[k1] in o1 )
o1[elem[k1]] = elem;
};

// =============================================================================

NodeList.prototype.findIndex = function( func ): number
@@ -152,5 +241,49 @@ Element.prototype.$$ =

// =============================================================================

Number.prototype.toSizeString = function(): string
{
const sizes = ['B', 'KiB', 'MiB', 'GiB'];

if( !this )
return '0 B';
const index = ~~Math.floor( Math.log(this) / Math.log(1024) );

if( !index )
return `${this} ${sizes[index]}`;

return `${(this / (1024 ** index)).toFixed(2)} ${sizes[index]}`;
};

Number.prototype.toDateString = function(): string
{
const date = new Date( this * 1000 );

const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const hours = date.getHours();
const minutes = date.getMinutes();

return (hours > 9 ? hours : "0" + hours) + ":" +
(minutes > 9 ? minutes : "0" + minutes) + " - " +
(day > 9 ? day : "0" + day) + "/" +
(month > 9 ? month : "0" + month) + "/" + year;
};

// =============================================================================

String.prototype.formatArgs = function( args: any[] ): string
{
return this.replace( /{(\d+)}/g, (match: string, index: number) =>
{
return args[index]
? args[index]
: match;
} );
};

// =============================================================================

Document.prototype.$ = $;
Document.prototype.$$ = $$;

+ 15
- 8
public/themes/pluto/src.static/controls/CheckBox.ts View File

@@ -13,6 +13,8 @@
* this program. If not, see <http://www.licenses.aculo.pl/>.
*/

// =============================================================================

/**
* Klasa kontrolki przycisku wyboru.
*
@@ -33,7 +35,7 @@ class CheckBox
*/
private static _current: HTMLElement = null;

// =============================================================================
// -----------------------------------------------------------------------------

/**
* Oryginalny przycisk wyboru względem którego wyłapywane będzie skupienie.
@@ -56,7 +58,7 @@ class CheckBox
*/
private _control: HTMLElement = null;

// =============================================================================
// -----------------------------------------------------------------------------

/**
* Konstruktor kontrolki.
@@ -73,6 +75,10 @@ class CheckBox
// sprawdź czy oryginalny przycisk wyboru został znaleziony
if( this._input == null )
{
Logger.Warning(
"check",
"Original checkbox input was not found for current tag"
);
this._failed = true;
return;
}
@@ -84,7 +90,7 @@ class CheckBox
this._addEvents();
}

// =============================================================================
// -----------------------------------------------------------------------------

/**
* Dodaje zdarzenia do kontrolki.
@@ -136,11 +142,15 @@ class CheckBox

if( selectme )
{
Logger.Info( "check", "Input state: unchecked" );

this._input.checked = !selectme;
this._control.classList.remove( "checked" );
}
else
{
Logger.Info( "check", "Input state: checked" );

this._input.checked = !selectme;
this._control.classList.add( "checked" );
}
@@ -189,8 +199,7 @@ class CheckBox
if( this._failed )
return;

if( !this._control.classList.contains("focused") )
this._control.classList.add( "focused" );
this._control.classList.add( "focused" );
}

/**
@@ -222,8 +231,6 @@ class CheckBox
return;
}
}

if( this._control.classList.contains("focused") )
this._control.classList.remove( "focused" );
this._control.classList.remove( "focused" );
}
}

+ 354
- 392
public/themes/pluto/src.static/controls/FileManager.ts
File diff suppressed because it is too large
View File


+ 85
- 37
public/themes/pluto/src.static/controls/TabControl.ts View File

@@ -13,6 +13,8 @@
* this program. If not, see <http://www.licenses.aculo.pl/>.
*/

// =============================================================================

/**
* Klasa kontrolki zawierającej zakładki.
*
@@ -23,9 +25,9 @@
* musi być do niej podpięty przy użyciu parametru 'data-variant', gdzie
* sprawdzany jest z parametrem 'data-id' zakładki.
*
* Aby jednak kontrolka podczas tworzenia mogłą znaleźć podpięte elementy
* należy zdefiniować dla niej parametr 'data-search' który ma zawierać
* regułę dla funkcji 'querySelectorAll', która szuka podpiętych elementów.
* Aby jednak kontrolka podczas tworzenia mogła znaleźć podpięte elementy,
* należy zdefiniować dla niej parametr 'data-search' który musi zawierać
* regułę dla funkcji 'querySelectorAll', szukającą podpiętych elementów.
* Dodatkowo parametr 'data-form' pozwala na zawężenie wyszukiwania danych
* do konkretnego formularza.
*
@@ -121,7 +123,7 @@ class TabControl
*/
private _failed: boolean = false;

// =============================================================================
// -----------------------------------------------------------------------------

/**
* Konstruktor kontrolki.
@@ -142,36 +144,59 @@ class TabControl

if( !this._form )
{
this._failed = true;
this._failed = Logger.$( "tab", "NoAttrElem", "data-form" );
return;
}

// wiadomość w przypadku gdy model jest oznaczony jako nieistniejący
// wiadomość w przypadku gdy model dla zakładki nie istnieje
if( tab.dataset.message )
{
this._message = this._form.$<HTMLElement>( tab.dataset.message );
this._flags = this._form.$$<HTMLInputElement>( "input[data-mflag" );
}
else
{
this._message = null;
this._flags = null;
this._flags = this._form.$$<HTMLInputElement>("input[data-mflag]");

if( !this._message )
{
this._failed = Logger.$( "tab", "NoAttrElem", "data-message" );
return;
}
if( !this._flags || this._flags.length == 0 )
{
this._failed = Logger.Warning(
"tab",
"Missing input fields that should contain status for tabs"
);
return;
}
}

// przycisk usuwania danych z zakładki
if( tab.dataset.remove )
{
this._remove = this._form.$<HTMLElement>( tab.dataset.remove );
if( !this._remove )
{
this._failed = Logger.$( "tab", "NoAttrElem", "data-remove" );
return;
}
}

// przycisk dodawania danych do zakładki
if( tab.dataset.create )
{
this._create = this._form.$<HTMLElement>( tab.dataset.create );
if( !this._create )
{
this._failed = Logger.$( "tab", "NoAttrElem", "data-create" );
return;
}
}

// element w którym wyszukiwane są warianty
this._search = this._form.$<HTMLElement>( tab.dataset.search );

if( !this._search )
{
this._failed = true;
this._failed = Logger.$( "tab", "NoAttrElem", "data-search" );
return;
}

@@ -179,13 +204,25 @@ class TabControl
this._variants = this._search.$$<HTMLElement>( "[data-variant]" );

if( !this._variants || this._variants.length === 0 )
this._failed = true;
{
this._failed = Logger.Warning(
"tab",
"Missing variants that tab controls"
);
return;
}

// lista zakładek w kontrolce
this._tabs = tab.$$<HTMLLIElement>( "li" );

if( !this._tabs || this._tabs.length === 0 )
this._failed = true;
{
this._failed = Logger.Warning(
"tab",
"Missing 'li' elements that are used as tabs in control"
);
return;
}

this.addEvents();
}
@@ -230,8 +267,8 @@ class TabControl
if( !this._create || !this._remove )
return;

this._create.addEventListener( "click", this._onCreateLanguage );
this._remove.addEventListener( "click", this._onRemoveLanguage );
this._create.addEventListener( "click", this._onCreateModel );
this._remove.addEventListener( "click", this._onRemoveModel );
}

/**
@@ -245,10 +282,22 @@ class TabControl
*/
public selectTab( index: number, force: boolean = false ): void
{
if( this._failed )
return;

// indeks poza zasięgiem
if( !(index in this._tabs) )
{
Logger.Warning( "tab", "Trying to select non existing tab" );
return;
}

// sprawdź czy zakładka nie jest czasem już zaznaczona
if( this._failed || (!force && this._selected === index)
|| !(index in this._tabs) )
if( !force && this._selected === index )
{
Logger.Info( "tab", "Chosen tab is already selected" );
return;
}

const newli = this._tabs[index];
const newid = newli.dataset.id;
@@ -261,16 +310,14 @@ class TabControl
this._tabs[this._selected].classList.remove( "selected" );
newli.classList.add( "selected" );

// pokaż pola przypisane do zakładki
for( let x = 0; x < this._variants.length; ++x )
{
const variant = this._variants[x];
Logger.Info( "tab", `Trying to select tab with index: ${index}` );

// pokaż pola przypisane do zakładki
for( const variant of this._variants )
if( variant.dataset.variant == newid )
variant.classList.remove( "hidden" );
else if( variant.dataset.variant == oldid )
variant.classList.add( "hidden" );
}

// razem ze zmianą zakładki zmienia się też tryb wyświetlania danych
if( this._message != null && this._flags.length > 0 )
@@ -279,10 +326,7 @@ class TabControl
const fname = `flag:${newid}`;

// przeszukuj wszystkie flagi
for( let x = 0; x < this._flags.length; ++x )
{
const flag = this._flags[x];

for( const flag of this._flags )
if( flag.name == fname && this._remove && this._create )
{
// i jeżeli flaga jest dopuszczona do widoku, wyświetl dane
@@ -303,12 +347,11 @@ class TabControl
}
break;
}
}
}
this._selected = index;
}

// =============================================================================
// -----------------------------------------------------------------------------

/**
* Akcja wywoływana podczas zmiany zakładki w kontrolce.
@@ -335,18 +378,18 @@ class TabControl
}

/**
* Akcja wywoływana po kliknięciu w przycisk tworzenia języka.
* Akcja wywoływana po kliknięciu w przycisk tworzenia modelu.
*
* DESCRIPTION:
* Wyświetla kontrolki formularza dla zaznaczonego języka ukrywając
* wiadomość o braku tłumaczenia.
* Wyświetla kontrolki formularza dla zaznaczonego modelu ukrywając
* wiadomość o braku danych.
* Dodatkowo zmienia flagę modelu używaną przy zapisie danych.
*
* PARAMETERS:
* ev: (MouseEvent)
* Argumenty zdarzenia.
*/
private _onCreateLanguage = ( ev: MouseEvent ): void =>
private _onCreateModel = ( ev: MouseEvent ): void =>
{
if( this._failed )
return;
@@ -359,6 +402,8 @@ class TabControl
if( index === -1 )
return;

Logger.Info( "tab", `Creating model for tab with index: ${index}` );

this._create.classList.add( "hidden" );
this._remove.classList.remove( "hidden" );

@@ -367,10 +412,10 @@ class TabControl
}

/**
* Akcja wywoływana po kliknięciu w przycisk usuwania języka.
* Akcja wywoływana po kliknięciu w przycisk usuwania modelu.
*
* DESCRIPTION:
* Wyświetla wiadomość o braku tłumaczenia dla zaznaczonego języka
* Wyświetla wiadomość o braku tłumaczenia dla zaznaczonego modelu
* ukrywając kontrolki formularza.
* Dodatkowo zmienia flagę modelu używaną przy zapisie danych.
*
@@ -378,11 +423,12 @@ class TabControl
* ev: (MouseEvent)
* Argumenty zdarzenia.
*/
private _onRemoveLanguage = ( ev: MouseEvent ): void =>
private _onRemoveModel = ( ev: MouseEvent ): void =>
{
if( this._failed || !("confirm" in this._remove.dataset) )
return;

// wyświetl potwierdzenie - czy na pewno usunąć dany model
if( !window.confirm( this._remove.dataset.confirm ) )
return;

@@ -394,6 +440,8 @@ class TabControl
if( index === -1 )
return;

Logger.Info( "tab", `Removing model for tab with index: ${index}` );

this._remove.classList.add( "hidden" );
this._create.classList.remove( "hidden" );


+ 28
- 2
public/themes/pluto/src.static/extra/ObservableArray.ts View File

@@ -1,4 +1,30 @@
/*
* This file is part of Pulsar CMS
* Copyright (c) by sobiemir <sobiemir@aculo.pl>
* ___ __
* / _ \__ __/ /__ ___ _____
* / ___/ // / (_-</ _ `/ __/
* /_/ \_,_/_/___/\_,_/_/
*
* This source file is subject to the New BSD License that is bundled
* with this package in the file LICENSE.txt.
*
* You should have received a copy of the New BSD License along with
* this program. If not, see <http://www.licenses.aculo.pl/>.
*/

// =============================================================================

/**
* Klasa tworząca tablicę obserwowanych wartości.
*
* DESCRIPTION:
* Każda zmiana w tablicy - dodawanie czy usuwanie elementu - odnotowywana
* jest w podpiętych do klasy funkcjach.
* Aby jednak zmiana mogła zostać odnotowana, każda operacja musi być
* wykonywana przy użyciu wbudowanych w klasę funkcji.
* Własna zmiana lub dodanie elementu do tablicy nie zostanie odnotowane.
*/
class ObservableArray<TYPE>
{
/**
@@ -15,7 +41,7 @@ class ObservableArray<TYPE>
*/
protected _subscribers: IObservableFunction<TYPE>[];

// =============================================================================
// -----------------------------------------------------------------------------

/**
* Konstruktor klasy.
@@ -211,7 +237,7 @@ class ObservableArray<TYPE>
this._subscribers[x].func( this );
}

// =============================================================================
// -----------------------------------------------------------------------------

/**
* Pozwala na konwersję wartości do innego obiektu niż oryginalny.

+ 34
- 2
public/themes/pluto/src.static/extra/RenderArray.ts View File

@@ -1,4 +1,31 @@
/*
* This file is part of Pulsar CMS
* Copyright (c) by sobiemir <sobiemir@aculo.pl>
* ___ __
* / _ \__ __/ /__ ___ _____
* / ___/ // / (_-</ _ `/ __/
* /_/ \_,_/_/___/\_,_/_/
*
* This source file is subject to the New BSD License that is bundled
* with this package in the file LICENSE.txt.
*
* You should have received a copy of the New BSD License along with
* this program. If not, see <http://www.licenses.aculo.pl/>.
*/

// =============================================================================

/**
* Klasa tworząca tablicę wyświetlającą listę elementów przy użyciu szablonu.
*
* DESCRIPTION:
* Każdy wyświetlany element z listy korzysta z tego samego szablonu.
* Do przetwarzania szablonów wykorzystywana jest biblioteka doT.
* Przed użyciem należy zapoznać się z funkcją o nazwie "options", gdzie
* można ustawić opcje dotyczące przetwarzania i wyświetlania szablonu.
* Renderowanie (wyświetlanie) szablonu następuje automatycznie przy
* odświeżaniu listy elementów.
*/
class RenderArray<TYPE> extends ObservableArray<TYPE>
{
/**
@@ -22,9 +49,14 @@ class RenderArray<TYPE> extends ObservableArray<TYPE>
*/
protected _single: boolean;

/**
* Obiekt główny w szablonie, zazwyczaj jest to "this".
*
* TYPE: any
*/
protected _callObject: any;

// =============================================================================
// -----------------------------------------------------------------------------

/**
* Konstruktor klasy.
@@ -88,7 +120,7 @@ class RenderArray<TYPE> extends ObservableArray<TYPE>
super.runSubscribers();
}

// =============================================================================
// -----------------------------------------------------------------------------

/**
* Renderuje elementy z obserwowanej tablicy w aplikacji.

+ 60
- 2
public/themes/pluto/src.static/extra/RenderArrayTree.ts View File

@@ -1,4 +1,34 @@
/*
* This file is part of Pulsar CMS
* Copyright (c) by sobiemir <sobiemir@aculo.pl>
* ___ __
* / _ \__ __/ /__ ___ _____
* / ___/ // / (_-</ _ `/ __/
* /_/ \_,_/_/___/\_,_/_/
*
* This source file is subject to the New BSD License that is bundled
* with this package in the file LICENSE.txt.
*
* You should have received a copy of the New BSD License along with
* this program. If not, see <http://www.licenses.aculo.pl/>.
*/

// =============================================================================

/**
* Klasa tworząca tablicę wyświetlającą drzewo elementów przy użyciu szablonu.
*
* DESCRIPTION:
* Każdy wyświetlany element z listy korzysta z tego samego szablonu.
* Do przetwarzania szablonów wykorzystywana jest biblioteka doT.
* Każdy z elementów może posiadać listę elementów podrzędnych (dzieci).
* Przed użyciem należy zapoznać się z funkcją o nazwie "options", gdzie
* można ustawić opcje dotyczące przetwarzania i wyświetlania szablonu.
* Drzewo można modyfikować również po utworzeniu, każda zmiana zostanie
* odnotowana w przypisanych do klasy funkcjach.
* Funkcje przypisywane do klasy nadrzędnej kopiowane są automatycznie do
* wszystkich klas podrzędnych (w głąb drzewa).
*/
class RenderArrayTree<TYPE> extends ObservableArray<TYPE>
{
/**
@@ -43,9 +73,14 @@ class RenderArrayTree<TYPE> extends ObservableArray<TYPE>
*/
protected _upper: IObservableValue<TYPE>;

/**
* Obiekt główny w szablonie, zazwyczaj jest to "this".
*
* TYPE: any
*/
protected _callObject: any;

// =============================================================================
// -----------------------------------------------------------------------------

/**
* Konstruktor klasy.
@@ -64,6 +99,17 @@ class RenderArrayTree<TYPE> extends ObservableArray<TYPE>
this._upper = upper;
}

/**
* Możliwe do ustawienia opcje dla klasy RenderArrayTree.
*
* DESCRIPTION:
* Opcje warto ustawić jeszcze przed wstawianiem elementów do tablicy.
* Zmiana opcji spowoduje odświeżenie widoku elementów.
*
* PARAMETERS:
* options: IRenderArrayTreeOptions
* Lista opcji do zmiany.
*/
public options( options: IRenderArrayTreeOptions ): void
{
if( options.childIndex )
@@ -81,11 +127,23 @@ class RenderArrayTree<TYPE> extends ObservableArray<TYPE>
this.runSubscribers();
}

/**
* Pobiera nadrzędną listę elementów do której odnosi się aktualna lista.
*
* RETURNS: RenderArrayTree<TYPE>
* Nadrzędna lista do której odnosi się jest aktualna lista.
*/
public getParent(): RenderArrayTree<TYPE>
{
return this._parent;
}

/**
* Pobiera element z listy nadrzędnej do którego przypisana jest lista.
*
* RETURNS: IObservableValue<TYPE>
* Element do którego przypisana jest lista.
*/
public getUpper(): IObservableValue<TYPE>
{
return this._upper;
@@ -149,7 +207,7 @@ class RenderArrayTree<TYPE> extends ObservableArray<TYPE>
upper.extra.child = observable;
}

// =============================================================================
// -----------------------------------------------------------------------------

/**
* Renderuje elementy z obserwowanej tablicy w aplikacji.

+ 96
- 2
public/themes/pluto/src.static/interfaces/IEntity.ts View File

@@ -1,20 +1,114 @@
/*
* This file is part of Pulsar CMS
* Copyright (c) by sobiemir <sobiemir@aculo.pl>
* ___ __
* / _ \__ __/ /__ ___ _____
* / ___/ // / (_-</ _ `/ __/
* /_/ \_,_/_/___/\_,_/_/
*
* This source file is subject to the New BSD License that is bundled
* with this package in the file LICENSE.txt.
*
* You should have received a copy of the New BSD License along with
* this program. If not, see <http://www.licenses.aculo.pl/>.
*/

// =============================================================================

/**
* Interfejs dla obiektu zawierającego informacje o elemencie.
*/
interface IEntity
{
/**
* Nazwa elementu.
*
* TYPE: string
*/
name: string;

/**
* Rozmiar elementu (tylko w przypadku pliku).
*
* TYPE: number
*/
size: number;

/**
* Data (timestamp) ostatniej modyfikacji elementu.
*
* TYPE: number
*/
modify: number;

/**
* Data (timestamp) ostatniego dostępu do elementu.
*
* TYPE: number
*/
access: number;

/**
* Typ elementu (plik / katalog / skrót).
*
* TYPE: string
*/
type: string;

/**
* Typ mime (np. text/plain) dla pliku, wzorowany na repozytorium httpd.
*
* TYPE: string
*/
mime: string;
}

interface IFolder
// =============================================================================

/**
* Interfejs dla obiektu zawierającego informacje o katalogu.
*/
interface IDirectory
{
/**
* Nazwa katalogu.
*
* TYPE: string
*/
name: string;

/**
* Data (timestamp) ostatniej modyfikacji.
*
* TYPE: number
*/
modify: number;

/**
* Data (timestamp) ostatniego dostępu do katalogu.
*
* TYPE: number
*/
access: number;
children: IFolder[];

/**
* Lista podkatalogów znajdujących się w katalogu.
*
* TYPE: IDirectory[]
*/
children: IDirectory[];

/**
* Czy katalog jest rozwinięty czy zwinięty?
*
* TYPE: boolean
*/
rolled: boolean;

/**
* Czy katalog został zaznaczony i jest otworzony?
*
* TYPE: boolean
*/
checked: boolean;
}

+ 205
- 26
public/themes/pluto/src.static/interfaces/IFileManager.ts View File

@@ -1,4 +1,23 @@
/*
* This file is part of Pulsar CMS
* Copyright (c) by sobiemir <sobiemir@aculo.pl>
* ___ __
* / _ \__ __/ /__ ___ _____
* / ___/ // / (_-</ _ `/ __/
* /_/ \_,_/_/___/\_,_/_/
*
* This source file is subject to the New BSD License that is bundled
* with this package in the file LICENSE.txt.
*
* You should have received a copy of the New BSD License along with
* this program. If not, see <http://www.licenses.aculo.pl/>.
*/

// =============================================================================

/**
* Interfejs zawierający informacje na temat przycisków menedżera plików.
*/
interface IFileManagerButtons
{
/**
@@ -30,25 +49,18 @@ interface IFileManagerButtons
toggleTree: HTMLElement;

/**
* Przycisk wgrywania nowego pliku do witryny.
*
* TYPE: HTMLElement
*/
upload: HTMLElement;

/**
* Przycisk tworzenia nowego folderu.
* Przycisk otwierający panel wgrywania nowego pliku do witryny.
*
* TYPE: HTMLElement
*/
newFolder: HTMLElement;
showUploadPanel: HTMLElement;

/**
* Przycisk otwierający szczegóły pliku.
* Przycisk otwierający panel tworzenia nowego katalogu.
*
* TYPE: HTMLElement
*/
details: HTMLElement;
showCreatePanel: HTMLElement;

/**
* Przycisk pozwalający na pobranie pliku.
@@ -58,32 +70,25 @@ interface IFileManagerButtons
download: HTMLAnchorElement;

/**
* Przycisk pozwalający na zmianę nazwy pliku lub folderu.
* Przycisk pozwalający na zmianę nazwy pliku lub katalogu.
*
* TYPE: HTMLElement
*/
rename: HTMLElement;

/**
* Przycisk pozwalający na usunięcie pliku lub folderu.
* Przycisk pozwalający na usunięcie pliku lub katalogu.
*
* TYPE: HTMLElement
*/
remove: HTMLElement;

/**
* Przycisk zamykania panelu informacji na temat pliku.
* Przycisk zamykania podglądu pliku.
*
* TYPE: HTMLElement
*/
closeInfo: HTMLElement;

/**
* Przycisk wyszukiwania elementu...
*
* TYPE: HTMLElement
*/
search: HTMLElement;
closePreview: HTMLElement;

/**
* Przycisk przewijania do następnego pliku.
@@ -104,14 +109,14 @@ interface IFileManagerButtons
*
* TYPE: HTMLAnchorElement
*/
getOpened: HTMLAnchorElement;
downloadCurrent: HTMLAnchorElement;

/**
* Przycisk wysyłania żądania dla tworzenia nowego folderu.
* Przycisk wysyłania żądania dla tworzenia nowego katalogu.
*
* TYPE: HTMLElement
*/
createFolder: HTMLElement;
createDirectory: HTMLElement;

/**
* Przycisk wysyłania żądania do wgrania plików.
@@ -121,6 +126,11 @@ interface IFileManagerButtons
uploadFile: HTMLElement;
}

// =============================================================================

/**
* Inferfejs zawierający szczegóły dotyczące wyświetlanego pliku.
*/
interface IFileManagerDetails
{
/**
@@ -152,9 +162,178 @@ interface IFileManagerDetails
modified: HTMLElement;

/**
* Informacja o wymiarach pliku.
* Informacja o rozmiarze pliku.
*
* TYPE: HTMLElement
*/
size: HTMLElement;
}

// =============================================================================

/**
* Interfejs zawierający panele używane w menedżerze plików.
*/
interface IFileManagerPanels
{
/**
* Panel wyświetlający drzewo katalogów.
*
* TYPE: HTMLElement
*/
directories: HTMLElement;

/**
* Panel wyświetlający listę plików.
*
* TYPE: HTMLElement
*/
entities: HTMLElement;

/**
* Panel wyświetlający szczegóły pliku.
*
* TYPE: HTMLElement
*/
details: HTMLElement;

/**
* Panel wyświetlający przyciski pod listą plików.
*
* TYPE: HTMLElement
*/
footer: HTMLElement;

/**
* Panel zawierający kontrolki służące dodawaniu nowego katalogu.
*
* TYPE: HTMLElement
*/
createDirectory: HTMLElement;

/**
* Panel zawierający kontrolki pozwalające na dodawanie plików.
*
* TYPE: HTMLFormElement
*/
uploadFile: HTMLFormElement;

/**
* Panel zawierający element wyświetlany podczas wczytywania plików.
*
* TYPE: HTMLElement
*/
entityLoader: HTMLElement;

/**
* Panel zawierający element wyświetlany podczas wczytywania katalogów.
*
* TYPE: HTMLElement
*/
directoryLoader: HTMLElement;

/**
* Panel boczny zawierający drzewo katalogów.
*
* TYPE: HTMLElement
*/
sidebar: HTMLElement;
}

// =============================================================================

/**
* Interfejs zawierający kontrolki używane w menedżerze plików.
*/
interface IFileManagerControls
{
/**
* Nazwa pliku lub aktualna pozycja użytkownika w drzewie katalogów.
*
* TYPE: HTMLElement
*/
title: HTMLElement;

/**
* Kontrolka wyświetlająca podgląd obrazków.
*
* TYPE: HTMLImageElement
*/
imagePreview: HTMLImageElement;

/**
* Kontrolka wyświetlająca podgląd dla plików.
*
* TYPE: HTMLTextAreaElement
*/
filePreview: HTMLTextAreaElement;

/**
* Nazwa tworzonego obiektu.
*
* TYPE: HTMLInputElement
*/
entityName: HTMLInputElement;

/**
* Kontrolka wyboru plików do wgrywania.
*
* TYPE: HTMLInputElement
*/
uploadFile: HTMLInputElement;

/**
* Lista plików do wgrania wyświetlanych w kontrolce.
*
* TYPE: HTMLInputElement
*/
selectedFiles: HTMLInputElement;
}

// =============================================================================

/**
* Interfejs zawierający opcje używane podczas inicjalizacji menedżera plików.
*/
interface IFileManagerOptions
{
/**
* Element główny menedżera plików.
*
* TYPE: HTMLElement
*/
element: HTMLElement;

/**
* Selektor względem którego wstawiane będą kolejne elementy w drzewie.
*
* TYPE: string
*/
treeSelector: string;

/**
* Indeks do obiektu posiadającego dzieci.
*
* TYPE: string
*/
childIndex: string;

/**
* Szablon dla pojedynczego katalogu w drzewie.
*
* TYPE: string | doT.RenderFunction
*/
directoryTemplate?: string;

/**
* Szablon dla pojedynczego elementu w liście.
*
* TYPE: string | doT.RenderFunction
*/
entityTemplate?: string;

actionClasses: {
showSidebar: string;
hideSidebar: string;
};
}

+ 66
- 0
public/themes/pluto/src.static/interfaces/IObservable.ts View File

@@ -1,17 +1,83 @@
/*
* This file is part of Pulsar CMS
* Copyright (c) by sobiemir <sobiemir@aculo.pl>
* ___ __
* / _ \__ __/ /__ ___ _____
* / ___/ // / (_-</ _ `/ __/
* /_/ \_,_/_/___/\_,_/_/
*
* This source file is subject to the New BSD License that is bundled
* with this package in the file LICENSE.txt.
*
* You should have received a copy of the New BSD License along with
* this program. If not, see <http://www.licenses.aculo.pl/>.
*/

// =============================================================================

/**
* Inferfejs dla obserwowanego obiektu.
*/
interface IObservableValue<TYPE>
{
/**
* Element renderowany przez klasę wstawiany przy odświeżaniu elementów.
*
* TYPE: HTMLElement
*/
element: HTMLElement;

/**
* Aktualna wartość elementu w liście.
*
* TYPE: TYPE
*/
value: TYPE;

/**
* Czy element wymaga aktualizacji przy odświeżaniu?
*
* TYPE: boolean
*/
needUpdate: boolean;

/**
* Czy element był aktualizowany?
*
* TYPE: boolean
*/
wasUpdated: boolean;

/**
* Dodatkowe informacje na temat obiektu zależne od obserwującej klasy.
*
* TYPE: any
*/
extra: any;
}

// =============================================================================

/**
* Interfejs zawierający informacje o subskrybującej funkcji.
*/
interface IObservableFunction<TYPE>
{
/**
* Nazwa indeksu do którego przypisywana jest funkcja.
*
* TYPE: string
*/
name: string;

/**
* Funkcja wywoływana przy odświeżaniu tablicy obserwowanych elementów.
*
* TYPE: TObservableArrayFunc<TYPE>
*/
func: TObservableArrayFunc<TYPE>;
}

// =============================================================================

type TObservableArrayFunc<TYPE> = (obs: ObservableArray<TYPE>) => void;

+ 111
- 0
public/themes/pluto/src.static/interfaces/IRender.ts View File

@@ -1,23 +1,134 @@
/*
* This file is part of Pulsar CMS
* Copyright (c) by sobiemir <sobiemir@aculo.pl>
* ___ __
* / _ \__ __/ /__ ___ _____
* / ___/ // / (_-</ _ `/ __/
* /_/ \_,_/_/___/\_,_/_/
*
* This source file is subject to the New BSD License that is bundled
* with this package in the file LICENSE.txt.
*
* You should have received a copy of the New BSD License along with
* this program. If not, see <http://www.licenses.aculo.pl/>.
*/

// =============================================================================

/**
* Interfejs zawierający dodatkowe dane dla renderowanego drzewa elementów.
*
* DESCRIPTION:
* Interfejs ten używany jest przy konwersji z wartości "any".
* Wartości przypisywane są w polu "extra", które znajduje się w interfejsie
* o nazwie IObservableValue.
*/
interface IRenderTreeExtra<TYPE>
{
/**
* Klasa nadrzędna (rodzic), zawierająca listę elementów.
*
* TYPE: RenderArrayTree<TYPE>
*/
owner?: RenderArrayTree<TYPE>;

/**
* Klasa podrzędna (dziecko), zawierająca listę elementów.
*
* TYPE: RenderArrayTree<TYPE>
*/
child?: RenderArrayTree<TYPE>;
}

// =============================================================================

/**
* Interfejs zawierający opcje możliwe do ustawienia dla klasy RenderArray.
*/
interface IRenderArrayOptions
{
/**
* Czy szablon ma być generowany osobno dla każdego elementu czy w całości.
*
* TYPE: boolean
*/
single?: boolean;

/**
* Szablon z którego generowane będą elementy lub całość.
*
* DESCRIPTION:
* Od tego czy szablon będzie renderowany osobno dla każdego elementu
* czy w całości zależy ustawienie pola "single".
* Wartością tego pola może być szablon który będzie kompilowany dopiero
* podczas ustawiania opcji lub funkcja reprezentująca wygenerowany
* szablon.
*
* TYPE: string | doT.RenderFunction
*/
template?: string | doT.RenderFunction;

/**
* Element do którego wrzucany będzie szablon.
*
* TYPE: HTMLElement
*/
place?: HTMLElement;

/**
* Obiekt główny używany w zasięgu kompilowanego szablonu.
*
* TYPE: any
*/
callObject?: any;
}

// =============================================================================

/**
* Interfejs zawierający opcje możliwe do ustawienia dla klasy RenderArrayTree.
*/
interface IRenderArrayTreeOptions
{
/**
* Selektor wybierający elementy do których mają być renderowane szablony.
*
* TYPE: string
*/
treeSelector?: string;

/**
* Szablon z którego generowane będą elementy lub całość.
*
* DESCRIPTION:
* Od tego czy szablon będzie renderowany osobno dla każdego elementu
* czy w całości zależy ustawienie pola "single".
* Wartością tego pola może być szablon który będzie kompilowany dopiero
* podczas ustawiania opcji lub funkcja reprezentująca wygenerowany
* szablon.
*
* TYPE: string | doT.RenderFunction
*/
template?: string | doT.RenderFunction;

/**
* Element do którego wrzucany będzie szablon.
*
* TYPE: HTMLElement
*/
place?: HTMLElement;

/**
* Nazwa pola zawierającego listę dzieci w oryginalnym obiekcie.
*
* TYPE: string
*/
childIndex?: string;

/**
* Obiekt główny używany w zasięgu kompilowanego szablonu.
*
* TYPE: any
*/
callObject?: any;
}

+ 2
- 1
public/themes/pluto/src.static/tsconfig.json View File

@@ -21,6 +21,7 @@
"controls/TabControl.ts",
"controls/FileManager.ts",
"Application.ts",
"Prototypes.ts"
"Prototypes.ts",
"Logger.ts"
]
}

+ 88
- 45
pulsar/admin/views/pluto/filemanager/index.volt View File

@@ -6,21 +6,22 @@
<h2 class="mb5 mt5">Menedżer plików</h2>
</div>
<!-- menedżer plików -->
<section class="filemanager white-back fill-free items-horizontal">
<section id="filemanager" class="white-back fill-free items-horizontal">

<!-- panel z drzewem folderów -->
<aside id="FM_E-Sidebar" class="sidebar lightgrey-back items-vertical">
<aside data-panel="sidebar" class="lightgrey-back items-vertical">
<div class="breadcrumb items-horizontal">
<!-- przycisk przejścia do głównego katalogu -->
<i id="FM_B-Home" class="fa fa-home"></i>
<i data-button="home" class="fa fa-home"></i>
<span class="fill-free"></span>
<!-- przycisk odświeżania -->
<i id="FM_B-Refresh" class="fa fa-refresh"></i>
<i data-button="refresh" class="fa fa-refresh"></i>
</div>

<!-- drzewo katalogów -->
<div class="directory-panel fill-free p05">
<div id="FM_E-Directory" class="loader"></div>
<ul class="directory-tree">
<div data-panel="directoryLoader" class="loader"></div>
<ul data-panel="directories" class="directory-tree">
</ul>
</div>
</aside>
@@ -29,89 +30,131 @@
<div class="fill-free items-vertical">
<div class="breadcrumb items-horizontal">
<!-- przełączanie paska z drzewem katalogów -->
<i id="FM_B-ToggleTree" class="fa fa-arrow-circle-o-left"></i>
<i data-button="toggleTree"
class="fa fa-arrow-circle-o-left"></i>
<!-- przejście do góry w drzewie katalogów -->
<i id="FM_B-Up" class="fa fa-level-up"></i>
<p class="title root fill-free">Pulsar</p>
<i data-button="up" class="fa fa-level-up"></i>

<!-- tytuł -->
<p data-control="title" class="title root fill-free">
Pulsar
</p>
<!-- dodawanie nowego pliku -->
<i id="FM_B-Upload" class="fa fa-upload"></i>
<i data-button="showUploadPanel" class="fa fa-upload"></i>
<!-- tworzenie nowego folderu -->
<i id="FM_B-NewFolder" class="fa fa-folder"></i>
<i data-button="showCreatePanel" class="fa fa-folder"></i>
<!-- pobieranie aktualnie otwartego pliku -->
<a href="#" id="FM_B-GetOpened" class="fa fa-download hidden">
</a>
<a data-button="downloadCurrent" href="#"
class="fa fa-download hidden"></a>

<!-- otwieranie poprzedniego pliku na liście -->
<i id="FM_B-PrevFile" class="fa fa-chevron-left hidden"></i>
<i data-button="prevFile"
class="fa fa-chevron-left hidden"></i>
<!-- otwieranie następnego pliku na liście -->
<i id="FM_B-NextFile" class="fa fa-chevron-right hidden"></i>
<i data-button="nextFile"
class="fa fa-chevron-right hidden"></i>

<!-- zamykanie okna ze szczegółami pliku -->
<i id="FM_B-CloseInfo" class="fa fa-times hidden"></i>
<i data-button="closePreview" class="fa fa-times hidden"></i>
</div>
<div id="FM_E-FolderCreate"

<!-- panel tworzenia katalogu -->
<div data-panel="createDirectory"
class="breadcrumb items-horizontal hidden">
<i class="fa fa-folder icononly"></i>
<input id="FM_E-FolderName" type="text" class="fill-free" />
<button id="FM_B-CreateDir" class="button simple">
<input data-control="entityName" type="text"
class="fill-free" />
<button data-button="createDirectory" class="button simple">
<i class="fa fa-plus"></i>Utwórz
</button>
</div>
<form id="FM_E-FileUpload" action="" method="post"

<!-- panel wgrywania pliku -->
<form data-panel="uploadFile" action="" method="post"
class="breadcrumb items-horizontal hidden">
<label for="FM_E-FileName" class="button simple">
<label for="FM_IUpload" class="button simple">
<i class="fa fa-file"></i>Wybierz pliki
</label>
<input id="FM_E-FileName" name="upload_files" multiple
type="file" class="hidden" />
<input type="text" id="FM_E-FileList" class="fill-free"
value="Brak plików..." disabled>
<button type="submit" id="FM_B-UploadFile"
<input data-control="uploadFile" id="FM_IUpload"
name="upload_files" multiple type="file" class="hidden" />
<input data-control="selectedFiles" type="text"
class="fill-free" value="Brak plików..." disabled>
<button data-button="uploadFile" type="submit"
class="button simple">
<i class="fa fa-plus"></i>Dodaj wybrane
</button>
</form>
<!-- lista elementów -->
<div class="entity-panel fill-free p05">
<div id="FM_E-Entity" class="loader"></div>
<ul class="entities-list">
<div data-panel="entityLoader" class="loader"></div>

<!--
<form data-panel="uploadFile" action="" method="post"
class="popup light items-horizontal hidden">

<div class="container">
<label for="FM_IUpload" class="button simple">
<i class="fa fa-file"></i>Wybierz pliki
</label>
<input
data-control="uploadFile" id="FM_IUpload" multiple
name="upload_files" type="file" class="hidden" />
<input
data-control="fileList" type="text" disabled
class="fill-free" value="Brak plików...">
<button
data-button="uploadFile" type="submit"
class="button simple">
<i class="fa fa-plus"></i>
Dodaj wybrane
</button>
</div>
</form>
-->

<ul data-panel="entities" class="entities-list">
</ul>
<div id="FM_E-Details" class="hidden items-vertical">
<div class="img-details-container">
<textarea id="FM_E-FilePreview"></textarea>
<img id="FM_E-ImgPreview" src="" />
<div data-panel="details" class="details hidden items-vertical">
<div class="details-container">
<textarea data-control="filePreview"></textarea>
<img data-control="imagePreview" src="" />
</div>
<div id="FM_E-FileInfo">
<div class="file-info">
<dl>
<dt>Nazwa pliku:</dt>
<dd id="FM_D-Name"></dd>
<dd data-detail="name"></dd>

<dt>Typ:</dt>
<dd id="FM_D-Type"></dd>
<dd data-detail="type"></dd>

<dt>Zmodyfikowano:</dt>
<dd id="FM_D-Modified"></dd>
<dd data-detail="modified"></dd>

<dt>Rozmiar:</dt>
<dd id="FM_D-Size"></dd>
<dd data-detail="size"></dd>
</dl>
</div>
</div>
</div>
<!-- pasek sterowania katalogami -->
<div id="FM_E-Footer" class="breadcrumb bottom items-horizontal">
<a href="#" id="FM_B-Download" class="button simple disabled">
<div data-panel="footer" class="breadcrumb bottom items-horizontal">
<a href="#" data-button="download"
class="button simple disabled">
<i class="fa fa-download"></i>Pobierz
</a>
<span class="fill-free"></span>
<p id="FM_B-Rename" class="button simple disabled">
<p data-button="rename" class="button hidden simple disabled">
<i class="fa fa-pencil"></i>Zmień nazwę
</p>
<p id="FM_B-Remove" class="button simple disabled">
<p data-button="remove" class="button hidden simple disabled">
<i class="fa fa-trash"></i>Usuń
</p>
</div>
</div>

<!-- szablon dla pojedynczego elementu w liście plików -->
<script type="text/template" id="FM_T-EntityItem">
<script type="text/template" data-template="entity">
<li class="entity-entry">
<div class="ml-05 items-horizontal">
<i class="fa
@@ -126,7 +169,7 @@
<%? it.type == 'dir' %>
---
<%??%>
<%= this.humanReadableSize( it.size ) %>
<%= it.size.toSizeString() %>
<%?%>
</span>
<span class="fill-free-2 text-right">
@@ -137,14 +180,14 @@
<%?%>
</span>
<span class="mr-05 fill-free-2 text-right">
<%= this.formatDate( it.modify ) %>
<%= it.modify.toDateString() %>
</span>
</div>
</li>
</script>

<!-- szablon dla elementu w drzewie katalogów -->
<script type="text/template" id="FM_T-DirectoryItem">
<script type="text/template" data-template="directory">
<li class="dir-entry">
<div>
<p data-click="browse" class="items-horizontal">

+ 2
- 1
tsconfig.static.json View File

@@ -21,6 +21,7 @@
"public/themes/pluto/src.static/controls/TabControl.ts",
"public/themes/pluto/src.static/controls/FileManager.ts",
"public/themes/pluto/src.static/Application.ts",
"public/themes/pluto/src.static/Prototypes.ts"
"public/themes/pluto/src.static/Prototypes.ts",
"public/themes/pluto/src.static/Logger.ts"
]
}

Loading…
Cancel
Save