Merge branch 'master' of https://github.com/brunosimon/keppler
@@ -56,13 +56,16 @@ class App
|
|||||||
project.files.create_version( './folder-test/depth-test/test-3.js', fs.readFileSync( '../test-folder/folder-2/test-3-diff-4.js', 'utf8' ) )
|
project.files.create_version( './folder-test/depth-test/test-3.js', fs.readFileSync( '../test-folder/folder-2/test-3-diff-4.js', 'utf8' ) )
|
||||||
project.files.create_version( './folder-test/test-1.html', fs.readFileSync( '../test-folder/test-1.html', 'utf8' ) )
|
project.files.create_version( './folder-test/test-1.html', fs.readFileSync( '../test-folder/test-1.html', 'utf8' ) )
|
||||||
project.files.create_version( './folder-test/test-2.php', fs.readFileSync( '../test-folder/test-2.php', 'utf8' ) )
|
project.files.create_version( './folder-test/test-2.php', fs.readFileSync( '../test-folder/test-2.php', 'utf8' ) )
|
||||||
project.files.create_version( './folder-test/big-one.txt', 'content 4\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline' )
|
project.files.create_version( './folder-test/big-one.txt', 'line\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline' )
|
||||||
|
project.files.create_version( './folder-test/loooooooooooooooooooooooooooooooong-one.txt', 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz' )
|
||||||
|
|
||||||
project.files.create_version( './icons/test.js', 'Test icon' )
|
project.files.create_version( './icons/test.js', 'Test icon' )
|
||||||
project.files.create_version( './icons/test.html', 'Test icon' )
|
project.files.create_version( './icons/test.html', 'Test icon' )
|
||||||
project.files.create_version( './icons/test.sass', 'Test icon' )
|
project.files.create_version( './icons/test.sass', 'Test icon' )
|
||||||
project.files.create_version( './icons/test.scss', 'Test icon' )
|
project.files.create_version( './icons/test.scss', 'Test icon' )
|
||||||
project.files.create_version( './icons/test.less', 'Test icon' )
|
project.files.create_version( './icons/test.less', 'Test icon' )
|
||||||
|
project.files.create_version( './icons/test.stylus', 'Test icon' )
|
||||||
|
project.files.create_version( './icons/test.styl', 'Test icon' )
|
||||||
project.files.create_version( './icons/test.css', 'Test icon' )
|
project.files.create_version( './icons/test.css', 'Test icon' )
|
||||||
project.files.create_version( './icons/test.php', 'Test icon' )
|
project.files.create_version( './icons/test.php', 'Test icon' )
|
||||||
project.files.create_version( './icons/test.json', 'Test icon' )
|
project.files.create_version( './icons/test.json', 'Test icon' )
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ var gulp = require( 'gulp' ),
|
|||||||
plumber = require( 'gulp-plumber' ),
|
plumber = require( 'gulp-plumber' ),
|
||||||
gulp_rename = require( 'gulp-rename' ),
|
gulp_rename = require( 'gulp-rename' ),
|
||||||
gulp_stylus = require( 'gulp-stylus' ),
|
gulp_stylus = require( 'gulp-stylus' ),
|
||||||
|
nib = require( 'nib' ),
|
||||||
browser_sync = require( 'browser-sync' ).create();
|
browser_sync = require( 'browser-sync' ).create();
|
||||||
|
|
||||||
var path = '../';
|
var path = '../';
|
||||||
@@ -41,6 +42,7 @@ gulp.task( 'stylesheet', function()
|
|||||||
.pipe( gulp_sourcemaps.init() )
|
.pipe( gulp_sourcemaps.init() )
|
||||||
.pipe( plumber() )
|
.pipe( plumber() )
|
||||||
.pipe( gulp_stylus( {
|
.pipe( gulp_stylus( {
|
||||||
|
use : nib(),
|
||||||
compress: true,
|
compress: true,
|
||||||
} ) )
|
} ) )
|
||||||
.pipe( gulp_sourcemaps.write( '.' ) )
|
.pipe( gulp_sourcemaps.write( '.' ) )
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"gulp-sourcemaps": "^1.6.0",
|
"gulp-sourcemaps": "^1.6.0",
|
||||||
"gulp-stylus": "^2.5.0",
|
"gulp-stylus": "^2.5.0",
|
||||||
"gulp-uglify": "^1.1.0",
|
"gulp-uglify": "^1.1.0",
|
||||||
"gulp-watch": "^3.0.0"
|
"gulp-watch": "^3.0.0",
|
||||||
|
"nib": "^1.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<browserconfig>
|
||||||
|
<msapplication>
|
||||||
|
<tile>
|
||||||
|
<square150x150logo src="/mstile-150x150.png"/>
|
||||||
|
<TileColor>#da532c</TileColor>
|
||||||
|
</tile>
|
||||||
|
</msapplication>
|
||||||
|
</browserconfig>
|
||||||
|
After Width: | Height: | Size: 412 B |
|
After Width: | Height: | Size: 580 B |
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "Keppler",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "\/android-chrome-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image\/png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"theme_color": "#ffffff",
|
||||||
|
"display": "standalone"
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="260.000000pt" height="260.000000pt" viewBox="0 0 260.000000 260.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
<metadata>
|
||||||
|
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||||
|
</metadata>
|
||||||
|
<g transform="translate(0.000000,260.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M1158 2565 c-2 -2 -25 -6 -53 -9 -390 -51 -771 -326 -953 -691 -33
|
||||||
|
-66 -87 -215 -95 -261 -3 -16 -11 -54 -18 -84 -20 -81 -17 -365 4 -460 28
|
||||||
|
-128 56 -211 113 -325 119 -244 324 -449 569 -573 66 -33 219 -89 268 -98 18
|
||||||
|
-3 66 -12 107 -19 97 -17 341 -13 435 8 310 69 559 221 748 458 131 164 214
|
||||||
|
348 262 584 14 66 13 331 -1 410 -33 185 -111 377 -215 525 -29 41 -96 118
|
||||||
|
-148 170 -244 242 -549 367 -896 368 -68 0 -125 -2 -127 -3z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 951 B |
@@ -0,0 +1,643 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File/Folder tree
|
||||||
|
*/
|
||||||
|
function FileTree( _options )
|
||||||
|
{
|
||||||
|
this._constructor( _options )
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create tree and add ./ folder
|
||||||
|
* @param {Object} _options
|
||||||
|
* @param {Boolean} _options.auto_wash - Should clean empty folder on removes
|
||||||
|
*/
|
||||||
|
FileTree.prototype._constructor = function( _options = {} )
|
||||||
|
{
|
||||||
|
if( typeof _options !== 'object' )
|
||||||
|
{
|
||||||
|
console.warn( 'constructor: _options should be an object' )
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options
|
||||||
|
this.auto_wash = typeof _options.auto_wash === 'undefined' ? false : _options.auto_wash
|
||||||
|
|
||||||
|
// Set up
|
||||||
|
this.folders = {}
|
||||||
|
|
||||||
|
// Initial folder
|
||||||
|
this.add_folder( '.', {} )
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean path
|
||||||
|
* @param {String} _path - Path to clean
|
||||||
|
* @return {String} Cleaned path
|
||||||
|
*/
|
||||||
|
FileTree.prototype.clean_path = function( _path )
|
||||||
|
{
|
||||||
|
// Errors
|
||||||
|
if( typeof _path !== 'string' )
|
||||||
|
{
|
||||||
|
console.warn( 'clean_path: _path should be a string' )
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim
|
||||||
|
_path = _path.trim()
|
||||||
|
|
||||||
|
// Repeating `/`
|
||||||
|
_path = _path.replace( /\/+/g, '/' )
|
||||||
|
|
||||||
|
// Ending `/`
|
||||||
|
_path = _path.replace( /\/$/, '' )
|
||||||
|
|
||||||
|
// Starting `/`
|
||||||
|
_path = _path.replace( /^\//, '' )
|
||||||
|
|
||||||
|
// Missing starting `./`
|
||||||
|
if( _path !== '.' && _path.search( './' ) !== 0 )
|
||||||
|
_path = './' + _path
|
||||||
|
|
||||||
|
return _path
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a folder
|
||||||
|
* Can create nested folder in one path
|
||||||
|
* @param {String} _path - Path to the folder (start with `./`)
|
||||||
|
* @param {Object} _data - Properties to add to the folder
|
||||||
|
* @returns {Object} Created folder
|
||||||
|
*/
|
||||||
|
FileTree.prototype.add_folder = function( _path, _data = {} )
|
||||||
|
{
|
||||||
|
// Errors
|
||||||
|
if( typeof _path !== 'string' )
|
||||||
|
{
|
||||||
|
console.warn( 'add_folder: _path should be a string' )
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if( typeof _data !== 'object' )
|
||||||
|
{
|
||||||
|
console.warn( 'add_folder: _data should be an object' )
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up
|
||||||
|
var path = this.clean_path( _path ),
|
||||||
|
path_parts = path.split( '/' ),
|
||||||
|
folders = this.folders,
|
||||||
|
folder = null
|
||||||
|
|
||||||
|
// Each path part
|
||||||
|
for( var _part of path_parts )
|
||||||
|
{
|
||||||
|
// Already exist
|
||||||
|
if( typeof folders[ _part ] !== 'undefined' )
|
||||||
|
{
|
||||||
|
folder = folders[ _part ]
|
||||||
|
folders = folder.folders
|
||||||
|
}
|
||||||
|
|
||||||
|
// Folder doesn't exist
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create folder
|
||||||
|
folder = {
|
||||||
|
folders: {},
|
||||||
|
files : {},
|
||||||
|
name : _part,
|
||||||
|
data : _data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save
|
||||||
|
folders[ _part ] = folder
|
||||||
|
folders = folder.folders
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return
|
||||||
|
return folder
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a file
|
||||||
|
* Will create folders if needed
|
||||||
|
* @param {String} _path - Path to the folder (start with `./`)
|
||||||
|
* @param {Object} _data - Properties to add to the file
|
||||||
|
* @returns {Object} Created file
|
||||||
|
*/
|
||||||
|
FileTree.prototype.add_file = function( _path, _data = {} )
|
||||||
|
{
|
||||||
|
// Errors
|
||||||
|
if( typeof _path !== 'string' )
|
||||||
|
{
|
||||||
|
console.warn( 'add_file: _path should be a string' )
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if( typeof _data !== 'object' )
|
||||||
|
{
|
||||||
|
console.warn( 'add_file: _data should be an object' )
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up
|
||||||
|
var path = this.clean_path( _path ),
|
||||||
|
path_parts = path.split( '/' ),
|
||||||
|
file_part = path_parts.pop()
|
||||||
|
|
||||||
|
// Create folder
|
||||||
|
var folder = this.add_folder( path_parts.join( '/' ) )
|
||||||
|
|
||||||
|
// Create file
|
||||||
|
var file = {
|
||||||
|
name: file_part,
|
||||||
|
data: _data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save
|
||||||
|
folder.files[ file_part ] = file
|
||||||
|
|
||||||
|
return file
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove folder
|
||||||
|
* Will delete contained folders and contained files
|
||||||
|
* @param {String} _path - Folder to delete (start with `./`)
|
||||||
|
* @returns {Boolean} Folder deleted or not
|
||||||
|
*/
|
||||||
|
FileTree.prototype.remove_folder = function( _path )
|
||||||
|
{
|
||||||
|
// Recursive emptying
|
||||||
|
function empty_folder( folder )
|
||||||
|
{
|
||||||
|
// Delete folders
|
||||||
|
for( var _folder_key in folder.folders )
|
||||||
|
{
|
||||||
|
var _folder = folder.folders[ _folder_key ]
|
||||||
|
|
||||||
|
empty_folder( _folder )
|
||||||
|
|
||||||
|
delete folder.folders[ _folder_key ]
|
||||||
|
|
||||||
|
// Callback
|
||||||
|
if( typeof _folder.data.on_remove === 'function' )
|
||||||
|
{
|
||||||
|
_folder.data.on_remove.apply( this, [ _folder ] )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete files
|
||||||
|
for( var _file_key in folder.files )
|
||||||
|
{
|
||||||
|
var _file = folder.files[ _file_key ]
|
||||||
|
|
||||||
|
delete folder.files[ _file_key ]
|
||||||
|
|
||||||
|
// Callback
|
||||||
|
if( typeof _file.data.on_remove === 'function' )
|
||||||
|
{
|
||||||
|
_file.data.on_remove.apply( this, [ _file ] )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errors
|
||||||
|
if( typeof _path !== 'string' )
|
||||||
|
{
|
||||||
|
console.warn( 'remove_folder: _path should be a string' )
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up
|
||||||
|
var path = this.clean_path( _path ),
|
||||||
|
path_parts = path.split( '/' ),
|
||||||
|
folder_part = path_parts.pop(),
|
||||||
|
folders = this.folders,
|
||||||
|
folder = null
|
||||||
|
|
||||||
|
// Each path part
|
||||||
|
for( var _part of path_parts )
|
||||||
|
{
|
||||||
|
// Found
|
||||||
|
if( typeof folders[ _part ] !== 'undefined' )
|
||||||
|
{
|
||||||
|
folder = folders[ _part ]
|
||||||
|
folders = folder.folders
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found
|
||||||
|
else
|
||||||
|
{
|
||||||
|
folder = null
|
||||||
|
folders = null
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Found
|
||||||
|
if( folders && folders[ folder_part ] )
|
||||||
|
{
|
||||||
|
var folder = folders[ folder_part ]
|
||||||
|
|
||||||
|
// Delete
|
||||||
|
empty_folder( folder )
|
||||||
|
delete folders[ folder_part ]
|
||||||
|
|
||||||
|
// Callback
|
||||||
|
if( typeof folder.data.on_remove === 'function' )
|
||||||
|
{
|
||||||
|
folder.data.on_remove.apply( this, [ folder ] )
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto wash
|
||||||
|
if( this.auto_wash )
|
||||||
|
this.remove_empty_folders()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove file
|
||||||
|
* Will delete contained folders and contained files
|
||||||
|
* @param {String} _path - File to delete (start with `./`)
|
||||||
|
* @returns {Boolean} File deleted or not
|
||||||
|
*/
|
||||||
|
FileTree.prototype.remove_file = function( _path )
|
||||||
|
{
|
||||||
|
// Errors
|
||||||
|
if( typeof _path !== 'string' )
|
||||||
|
{
|
||||||
|
console.warn( 'remove_file: _path should be a string' )
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up
|
||||||
|
var path = this.clean_path( _path ),
|
||||||
|
path_parts = path.split( '/' ),
|
||||||
|
file_part = path_parts.pop(),
|
||||||
|
folders = this.folders,
|
||||||
|
folder = null
|
||||||
|
|
||||||
|
// Each path part
|
||||||
|
for( var _part of path_parts )
|
||||||
|
{
|
||||||
|
// Found
|
||||||
|
if( typeof folders[ _part ] !== 'undefined' )
|
||||||
|
{
|
||||||
|
folder = folders[ _part ]
|
||||||
|
folders = folder.folders
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found
|
||||||
|
else
|
||||||
|
{
|
||||||
|
folder = null
|
||||||
|
folders = null
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Folder found
|
||||||
|
if( folders && folder )
|
||||||
|
{
|
||||||
|
var file = folder.files[ file_part ]
|
||||||
|
|
||||||
|
if( typeof file !== 'undefined' )
|
||||||
|
{
|
||||||
|
// Delete
|
||||||
|
delete folder.files[ file_part ]
|
||||||
|
|
||||||
|
// Auto wash
|
||||||
|
if( this.auto_wash )
|
||||||
|
this.remove_empty_folders()
|
||||||
|
|
||||||
|
// Callback
|
||||||
|
if( typeof file.data.on_remove === 'function' )
|
||||||
|
{
|
||||||
|
file.data.on_remove.apply( this, [ file ] )
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get file
|
||||||
|
* @param {String} _path - Path to file
|
||||||
|
* @returns {Object} File
|
||||||
|
*/
|
||||||
|
FileTree.prototype.get_file = function( _path )
|
||||||
|
{
|
||||||
|
// Errors
|
||||||
|
if( typeof _path !== 'string' )
|
||||||
|
{
|
||||||
|
console.warn( 'get_file: _path should be a string' )
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up
|
||||||
|
var path = this.clean_path( _path ),
|
||||||
|
path_parts = path.split( '/' ),
|
||||||
|
file_part = path_parts.pop(),
|
||||||
|
folders = this.folders,
|
||||||
|
folder = null
|
||||||
|
|
||||||
|
// Each path part
|
||||||
|
for( var _part of path_parts )
|
||||||
|
{
|
||||||
|
// Found
|
||||||
|
if( typeof folders[ _part ] !== 'undefined' )
|
||||||
|
{
|
||||||
|
folder = folders[ _part ]
|
||||||
|
folders = folder.folders
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found
|
||||||
|
else
|
||||||
|
{
|
||||||
|
folder = null
|
||||||
|
folders = null
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Folder found
|
||||||
|
if( folders && folder )
|
||||||
|
{
|
||||||
|
var file = folder.files[ file_part ]
|
||||||
|
|
||||||
|
if( typeof file !== 'undefined' )
|
||||||
|
{
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get folder
|
||||||
|
* @param {String} _path - Path to folder
|
||||||
|
* @returns {Object} Folder
|
||||||
|
*/
|
||||||
|
FileTree.prototype.get_folder = function( _path )
|
||||||
|
{
|
||||||
|
// Errors
|
||||||
|
if( typeof _path !== 'string' )
|
||||||
|
{
|
||||||
|
console.warn( 'get_folder: _path should be a string' )
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up
|
||||||
|
var path = this.clean_path( _path ),
|
||||||
|
path_parts = path.split( '/' ),
|
||||||
|
folders = this.folders,
|
||||||
|
folder = null
|
||||||
|
|
||||||
|
// Each path part
|
||||||
|
for( var _part of path_parts )
|
||||||
|
{
|
||||||
|
// Already exist
|
||||||
|
if( typeof folders[ _part ] !== 'undefined' )
|
||||||
|
{
|
||||||
|
folder = folders[ _part ]
|
||||||
|
folders = folder.folders
|
||||||
|
}
|
||||||
|
|
||||||
|
// Folder doesn't exist
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return
|
||||||
|
return folder
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Browse every folders and remove empty ones
|
||||||
|
* @return {Number} Number of removed folders
|
||||||
|
*/
|
||||||
|
FileTree.prototype.remove_empty_folders = function()
|
||||||
|
{
|
||||||
|
// Set up
|
||||||
|
var removed_count = 0
|
||||||
|
|
||||||
|
// Recursive remove
|
||||||
|
function can_remove_folder( folder )
|
||||||
|
{
|
||||||
|
// Each folder inside current folder
|
||||||
|
for( var _folder_key in folder.folders )
|
||||||
|
{
|
||||||
|
// Try to remove folder
|
||||||
|
var _folder = folder.folders[ _folder_key ],
|
||||||
|
can_remove = can_remove_folder( _folder )
|
||||||
|
|
||||||
|
// Remove folder
|
||||||
|
if( can_remove )
|
||||||
|
{
|
||||||
|
removed_count++
|
||||||
|
|
||||||
|
// Delete
|
||||||
|
delete folder.folders[ _folder_key ]
|
||||||
|
|
||||||
|
// Callback
|
||||||
|
if( typeof _folder.data.on_remove === 'function' )
|
||||||
|
{
|
||||||
|
_folder.data.on_remove.apply( this, [ _folder ] )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can be removed
|
||||||
|
var folder_keys = Object.keys( folder.folders ),
|
||||||
|
files_keys = Object.keys( folder.files )
|
||||||
|
|
||||||
|
if( folder_keys.length === 0 && folder_keys.length === 0 )
|
||||||
|
{
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try from ./
|
||||||
|
can_remove_folder( this.folders[ '.' ] )
|
||||||
|
|
||||||
|
return removed_count
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describe the tree in ASCII (├ ─ │ └)
|
||||||
|
* @param {Boolean} _log - Directly log to console
|
||||||
|
* @param {Boolean} _colored - Colored tree (only work well in Chrome)
|
||||||
|
* @return {String} Tree
|
||||||
|
*/
|
||||||
|
FileTree.prototype.describe = function( _log = false, _colored = false )
|
||||||
|
{
|
||||||
|
// Set up
|
||||||
|
var string_tree = '',
|
||||||
|
depth = 0,
|
||||||
|
styles = []
|
||||||
|
|
||||||
|
function add_to_string( value, type = null )
|
||||||
|
{
|
||||||
|
if( _colored )
|
||||||
|
{
|
||||||
|
string_tree += '%c'
|
||||||
|
|
||||||
|
switch( type )
|
||||||
|
{
|
||||||
|
case 'structure':
|
||||||
|
styles.push( 'color:#999;' )
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'folder':
|
||||||
|
styles.push( 'color:#999;' )
|
||||||
|
break
|
||||||
|
case 'file':
|
||||||
|
styles.push( 'color:#333;font-weight:bold;' )
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
styles.push( '' )
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string_tree += value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursive describe
|
||||||
|
function describe_folder( folder, depth, last = [] )
|
||||||
|
{
|
||||||
|
// Set up
|
||||||
|
var folder_keys = Object.keys( folder.folders ),
|
||||||
|
file_keys = Object.keys( folder.files )
|
||||||
|
|
||||||
|
// Each folders
|
||||||
|
for( var i = 0; i < folder_keys.length; i++ )
|
||||||
|
{
|
||||||
|
// Set up
|
||||||
|
var _folder_key = folder_keys[ i ],
|
||||||
|
_folder = folder.folders[ _folder_key ]
|
||||||
|
|
||||||
|
// Add to tree string
|
||||||
|
add_to_string( '\n' )
|
||||||
|
|
||||||
|
for( var j = 0; j < depth; j++ )
|
||||||
|
{
|
||||||
|
if( j === depth - 1 )
|
||||||
|
{
|
||||||
|
if( i === folder_keys.length - 1 && file_keys.length === 0 )
|
||||||
|
add_to_string( ' └', 'structure' )
|
||||||
|
else
|
||||||
|
add_to_string( ' ├', 'structure' )
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( last[ j ] )
|
||||||
|
add_to_string( ' ', 'structure' )
|
||||||
|
else
|
||||||
|
add_to_string( ' │', 'structure' )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add_to_string( '─', 'structure' )
|
||||||
|
add_to_string( _folder.name, 'folder' )
|
||||||
|
add_to_string( '/', 'structure' )
|
||||||
|
|
||||||
|
// Last
|
||||||
|
last.push( i === folder_keys.length - 1 && file_keys.length === 0 )
|
||||||
|
|
||||||
|
// Continue
|
||||||
|
describe_folder( _folder, depth + 1, last )
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each files
|
||||||
|
for( var i = 0; i < file_keys.length; i++ )
|
||||||
|
{
|
||||||
|
// Set up
|
||||||
|
var _file_key = file_keys[ i ],
|
||||||
|
_file = folder.files[ _file_key ]
|
||||||
|
|
||||||
|
// Add to tree string
|
||||||
|
string_tree += '\n'
|
||||||
|
|
||||||
|
for( var j = 0; j < depth; j++ )
|
||||||
|
{
|
||||||
|
if( j === depth - 1 )
|
||||||
|
{
|
||||||
|
if( i === file_keys.length - 1 )
|
||||||
|
add_to_string( ' └', 'structure' )
|
||||||
|
else
|
||||||
|
add_to_string( ' ├', 'structure' )
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( last[ j ] )
|
||||||
|
add_to_string( ' ', 'structure' )
|
||||||
|
else
|
||||||
|
add_to_string( ' │', 'structure' )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add_to_string( '─', 'structure' )
|
||||||
|
add_to_string( _file.name, 'file' )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describe from ./
|
||||||
|
add_to_string( '.', 'folder' )
|
||||||
|
add_to_string( '/', 'structure' )
|
||||||
|
describe_folder( this.folders[ '.' ], depth + 1 )
|
||||||
|
|
||||||
|
// Log
|
||||||
|
if( _log )
|
||||||
|
{
|
||||||
|
console.log.apply(console, [ string_tree ].concat( styles ) )
|
||||||
|
}
|
||||||
|
|
||||||
|
return string_tree
|
||||||
|
};
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Tests
|
||||||
|
// */
|
||||||
|
// var tree = new FileTree( { auto_wash: false } )
|
||||||
|
|
||||||
|
// tree.add_folder( './hey/hoy', { active: false, notifs: 0 } )
|
||||||
|
// tree.add_folder( './hey/hoy/toto', { active: false, notifs: 0 } )
|
||||||
|
// tree.add_folder( './hey/hoy/tata', { active: false, notifs: 0 } )
|
||||||
|
|
||||||
|
// tree.add_file( './test-1.txt', { active: false, notifs: 0 } )
|
||||||
|
// tree.add_file( './hey/hoy/test-2.txt', { active: false, notifs: 0 } )
|
||||||
|
// tree.add_file( './hey/hoy/test-3.txt', { active: false, notifs: 0 } )
|
||||||
|
// tree.add_file( './hey/hoy/tata/test-4.txt', { active: false, notifs: 0 } )
|
||||||
|
// tree.add_file( './hey/hoy/toto/test-5.txt', { active: false, notifs: 0 } )
|
||||||
|
|
||||||
|
// tree.add_file( './hey/hoy/toto/test-6.txt', { active: false, notifs: 0, on_remove: function( file ){ console.log( 'removed file :', file ); } } )
|
||||||
|
// tree.remove_file( './hey/hoy/toto/test-6.txt' )
|
||||||
|
|
||||||
|
// tree.add_folder( './pwet', { on_remove: function( folder ){ console.log( 'removed folder :', folder ); } } )
|
||||||
|
// tree.add_folder( './pwet/uh', { on_remove: function( folder ){ console.log( 'removed folder :', folder ); } } )
|
||||||
|
// tree.remove_folder( './pwet' )
|
||||||
|
|
||||||
|
// tree.remove_file( './hey/hoy/test-2.txt' )
|
||||||
|
// tree.remove_folder( './hey' )
|
||||||
|
|
||||||
|
// tree.describe( true, true )
|
||||||
@@ -1,641 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File/Folder tree
|
|
||||||
*/
|
|
||||||
class Tree
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create tree and add ./ folder
|
|
||||||
* @param {Object} _options
|
|
||||||
* @param {Boolean} _options.auto_wash - Should clean empty folder on removes
|
|
||||||
*/
|
|
||||||
constructor( _options = {} )
|
|
||||||
{
|
|
||||||
if( typeof _options !== 'object' )
|
|
||||||
{
|
|
||||||
console.warn( 'constructor: _options should be an object' )
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options
|
|
||||||
this.auto_wash = typeof _options.auto_wash === 'undefined' ? false : _options.auto_wash
|
|
||||||
|
|
||||||
// Set up
|
|
||||||
this.folders = {}
|
|
||||||
|
|
||||||
// Initial folder
|
|
||||||
this.add_folder( '.', {} )
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clean path
|
|
||||||
* @param {String} _path - Path to clean
|
|
||||||
* @return {String} Cleaned path
|
|
||||||
*/
|
|
||||||
clean_path( _path )
|
|
||||||
{
|
|
||||||
// Errors
|
|
||||||
if( typeof _path !== 'string' )
|
|
||||||
{
|
|
||||||
console.warn( 'clean_path: _path should be a string' )
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trim
|
|
||||||
_path = _path.trim()
|
|
||||||
|
|
||||||
// Repeating `/`
|
|
||||||
_path = _path.replace( /\/+/g, '/' )
|
|
||||||
|
|
||||||
// Ending `/`
|
|
||||||
_path = _path.replace( /\/$/, '' )
|
|
||||||
|
|
||||||
// Starting `/`
|
|
||||||
_path = _path.replace( /^\//, '' )
|
|
||||||
|
|
||||||
// Missing starting `./`
|
|
||||||
if( _path !== '.' && _path.search( './' ) !== 0 )
|
|
||||||
_path = './' + _path
|
|
||||||
|
|
||||||
return _path
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a folder
|
|
||||||
* Can create nested folder in one path
|
|
||||||
* @param {String} _path - Path to the folder (start with `./`)
|
|
||||||
* @param {Object} _data - Properties to add to the folder
|
|
||||||
* @returns {Object} Created folder
|
|
||||||
*/
|
|
||||||
add_folder( _path, _data = {} )
|
|
||||||
{
|
|
||||||
// Errors
|
|
||||||
if( typeof _path !== 'string' )
|
|
||||||
{
|
|
||||||
console.warn( 'add_folder: _path should be a string' )
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if( typeof _data !== 'object' )
|
|
||||||
{
|
|
||||||
console.warn( 'add_folder: _data should be an object' )
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up
|
|
||||||
let path = this.clean_path( _path ),
|
|
||||||
path_parts = path.split( '/' ),
|
|
||||||
folders = this.folders,
|
|
||||||
folder = null
|
|
||||||
|
|
||||||
// Each path part
|
|
||||||
for( let _part of path_parts )
|
|
||||||
{
|
|
||||||
// Already exist
|
|
||||||
if( typeof folders[ _part ] !== 'undefined' )
|
|
||||||
{
|
|
||||||
folder = folders[ _part ]
|
|
||||||
folders = folder.folders
|
|
||||||
}
|
|
||||||
|
|
||||||
// Folder doesn't exist
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Create folder
|
|
||||||
folder = {
|
|
||||||
folders: {},
|
|
||||||
files : {},
|
|
||||||
name : _part,
|
|
||||||
data : _data
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save
|
|
||||||
folders[ _part ] = folder
|
|
||||||
folders = folder.folders
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
return folder
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a file
|
|
||||||
* Will create folders if needed
|
|
||||||
* @param {String} _path - Path to the folder (start with `./`)
|
|
||||||
* @param {Object} _data - Properties to add to the file
|
|
||||||
* @returns {Object} Created file
|
|
||||||
*/
|
|
||||||
add_file( _path, _data = {} )
|
|
||||||
{
|
|
||||||
// Errors
|
|
||||||
if( typeof _path !== 'string' )
|
|
||||||
{
|
|
||||||
console.warn( 'add_file: _path should be a string' )
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if( typeof _data !== 'object' )
|
|
||||||
{
|
|
||||||
console.warn( 'add_file: _data should be an object' )
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up
|
|
||||||
let path = this.clean_path( _path ),
|
|
||||||
path_parts = path.split( '/' ),
|
|
||||||
file_part = path_parts.pop()
|
|
||||||
|
|
||||||
// Create folder
|
|
||||||
let folder = this.add_folder( path_parts.join( '/' ) )
|
|
||||||
|
|
||||||
// Create file
|
|
||||||
let file = {
|
|
||||||
name: file_part,
|
|
||||||
data: _data
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save
|
|
||||||
folder.files[ file_part ] = file
|
|
||||||
|
|
||||||
return file
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove folder
|
|
||||||
* Will delete contained folders and contained files
|
|
||||||
* @param {String} _path - Folder to delete (start with `./`)
|
|
||||||
* @returns {Boolean} Folder deleted or not
|
|
||||||
*/
|
|
||||||
remove_folder( _path )
|
|
||||||
{
|
|
||||||
// Errors
|
|
||||||
if( typeof _path !== 'string' )
|
|
||||||
{
|
|
||||||
console.warn( 'remove_folder: _path should be a string' )
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up
|
|
||||||
let path = this.clean_path( _path ),
|
|
||||||
path_parts = path.split( '/' ),
|
|
||||||
folder_part = path_parts.pop(),
|
|
||||||
folders = this.folders,
|
|
||||||
folder = null
|
|
||||||
|
|
||||||
// Each path part
|
|
||||||
for( let _part of path_parts )
|
|
||||||
{
|
|
||||||
// Found
|
|
||||||
if( typeof folders[ _part ] !== 'undefined' )
|
|
||||||
{
|
|
||||||
folder = folders[ _part ]
|
|
||||||
folders = folder.folders
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not found
|
|
||||||
else
|
|
||||||
{
|
|
||||||
folder = null
|
|
||||||
folders = null
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Found
|
|
||||||
if( folders && folders[ folder_part ] )
|
|
||||||
{
|
|
||||||
// Recursive emptying
|
|
||||||
function empty_folder( folder )
|
|
||||||
{
|
|
||||||
// Delete folders
|
|
||||||
for( let _folder_key in folder.folders )
|
|
||||||
{
|
|
||||||
let _folder = folder.folders[ _folder_key ]
|
|
||||||
|
|
||||||
empty_folder( _folder )
|
|
||||||
|
|
||||||
delete folder.folders[ _folder_key ]
|
|
||||||
|
|
||||||
// Callback
|
|
||||||
if( typeof _folder.data.on_remove === 'function' )
|
|
||||||
{
|
|
||||||
_folder.data.on_remove.apply( this, [ _folder ] )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete files
|
|
||||||
for( let _file_key in folder.files )
|
|
||||||
{
|
|
||||||
let _file = folder.files[ _file_key ]
|
|
||||||
|
|
||||||
delete folder.files[ _file_key ]
|
|
||||||
|
|
||||||
// Callback
|
|
||||||
if( typeof _file.data.on_remove === 'function' )
|
|
||||||
{
|
|
||||||
_file.data.on_remove.apply( this, [ _file ] )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let folder = folders[ folder_part ]
|
|
||||||
|
|
||||||
// Delete
|
|
||||||
empty_folder( folder )
|
|
||||||
delete folders[ folder_part ]
|
|
||||||
|
|
||||||
// Callback
|
|
||||||
if( typeof folder.data.on_remove === 'function' )
|
|
||||||
{
|
|
||||||
folder.data.on_remove.apply( this, [ folder ] )
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto wash
|
|
||||||
if( this.auto_wash )
|
|
||||||
this.remove_empty_folders()
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove file
|
|
||||||
* Will delete contained folders and contained files
|
|
||||||
* @param {String} _path - File to delete (start with `./`)
|
|
||||||
* @returns {Boolean} File deleted or not
|
|
||||||
*/
|
|
||||||
remove_file( _path )
|
|
||||||
{
|
|
||||||
// Errors
|
|
||||||
if( typeof _path !== 'string' )
|
|
||||||
{
|
|
||||||
console.warn( 'remove_file: _path should be a string' )
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up
|
|
||||||
let path = this.clean_path( _path ),
|
|
||||||
path_parts = path.split( '/' ),
|
|
||||||
file_part = path_parts.pop(),
|
|
||||||
folders = this.folders,
|
|
||||||
folder = null
|
|
||||||
|
|
||||||
// Each path part
|
|
||||||
for( let _part of path_parts )
|
|
||||||
{
|
|
||||||
// Found
|
|
||||||
if( typeof folders[ _part ] !== 'undefined' )
|
|
||||||
{
|
|
||||||
folder = folders[ _part ]
|
|
||||||
folders = folder.folders
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not found
|
|
||||||
else
|
|
||||||
{
|
|
||||||
folder = null
|
|
||||||
folders = null
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Folder found
|
|
||||||
if( folders && folder )
|
|
||||||
{
|
|
||||||
let file = folder.files[ file_part ]
|
|
||||||
|
|
||||||
if( typeof file !== 'undefined' )
|
|
||||||
{
|
|
||||||
// Delete
|
|
||||||
delete folder.files[ file_part ]
|
|
||||||
|
|
||||||
// Auto wash
|
|
||||||
if( this.auto_wash )
|
|
||||||
this.remove_empty_folders()
|
|
||||||
|
|
||||||
// Callback
|
|
||||||
if( typeof file.data.on_remove === 'function' )
|
|
||||||
{
|
|
||||||
file.data.on_remove.apply( this, [ file ] )
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get file
|
|
||||||
* @param {String} _path - Path to file
|
|
||||||
* @returns {Object} File
|
|
||||||
*/
|
|
||||||
get_file( _path )
|
|
||||||
{
|
|
||||||
// Errors
|
|
||||||
if( typeof _path !== 'string' )
|
|
||||||
{
|
|
||||||
console.warn( 'get_file: _path should be a string' )
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up
|
|
||||||
let path = this.clean_path( _path ),
|
|
||||||
path_parts = path.split( '/' ),
|
|
||||||
file_part = path_parts.pop(),
|
|
||||||
folders = this.folders,
|
|
||||||
folder = null
|
|
||||||
|
|
||||||
// Each path part
|
|
||||||
for( let _part of path_parts )
|
|
||||||
{
|
|
||||||
// Found
|
|
||||||
if( typeof folders[ _part ] !== 'undefined' )
|
|
||||||
{
|
|
||||||
folder = folders[ _part ]
|
|
||||||
folders = folder.folders
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not found
|
|
||||||
else
|
|
||||||
{
|
|
||||||
folder = null
|
|
||||||
folders = null
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Folder found
|
|
||||||
if( folders && folder )
|
|
||||||
{
|
|
||||||
let file = folder.files[ file_part ]
|
|
||||||
|
|
||||||
if( typeof file !== 'undefined' )
|
|
||||||
{
|
|
||||||
return file
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get folder
|
|
||||||
* @param {String} _path - Path to folder
|
|
||||||
* @returns {Object} Folder
|
|
||||||
*/
|
|
||||||
get_folder( _path )
|
|
||||||
{
|
|
||||||
// Errors
|
|
||||||
if( typeof _path !== 'string' )
|
|
||||||
{
|
|
||||||
console.warn( 'get_folder: _path should be a string' )
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up
|
|
||||||
let path = this.clean_path( _path ),
|
|
||||||
path_parts = path.split( '/' ),
|
|
||||||
folders = this.folders,
|
|
||||||
folder = null
|
|
||||||
|
|
||||||
// Each path part
|
|
||||||
for( let _part of path_parts )
|
|
||||||
{
|
|
||||||
// Already exist
|
|
||||||
if( typeof folders[ _part ] !== 'undefined' )
|
|
||||||
{
|
|
||||||
folder = folders[ _part ]
|
|
||||||
folders = folder.folders
|
|
||||||
}
|
|
||||||
|
|
||||||
// Folder doesn't exist
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
return folder
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Browse every folders and remove empty ones
|
|
||||||
* @return {Number} Number of removed folders
|
|
||||||
*/
|
|
||||||
remove_empty_folders()
|
|
||||||
{
|
|
||||||
// Set up
|
|
||||||
var removed_count = 0
|
|
||||||
|
|
||||||
// Recursive remove
|
|
||||||
function can_remove_folder( folder )
|
|
||||||
{
|
|
||||||
// Each folder inside current folder
|
|
||||||
for( let _folder_key in folder.folders )
|
|
||||||
{
|
|
||||||
// Try to remove folder
|
|
||||||
let _folder = folder.folders[ _folder_key ],
|
|
||||||
can_remove = can_remove_folder( _folder )
|
|
||||||
|
|
||||||
// Remove folder
|
|
||||||
if( can_remove )
|
|
||||||
{
|
|
||||||
removed_count++
|
|
||||||
|
|
||||||
// Delete
|
|
||||||
delete folder.folders[ _folder_key ]
|
|
||||||
|
|
||||||
// Callback
|
|
||||||
if( typeof _folder.data.on_remove === 'function' )
|
|
||||||
{
|
|
||||||
_folder.data.on_remove.apply( this, [ _folder ] )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can be removed
|
|
||||||
let folder_keys = Object.keys( folder.folders ),
|
|
||||||
files_keys = Object.keys( folder.files )
|
|
||||||
|
|
||||||
if( folder_keys.length === 0 && folder_keys.length === 0 )
|
|
||||||
{
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try from ./
|
|
||||||
can_remove_folder( this.folders[ '.' ] )
|
|
||||||
|
|
||||||
return removed_count
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Describe the tree in ASCII (├ ─ │ └)
|
|
||||||
* @param {Boolean} _log - Directly log to console
|
|
||||||
* @param {Boolean} _colored - Colored tree (only work well in Chrome)
|
|
||||||
* @return {String} Tree
|
|
||||||
*/
|
|
||||||
describe( _log = false, _colored = false )
|
|
||||||
{
|
|
||||||
// Set up
|
|
||||||
var string_tree = '',
|
|
||||||
depth = 0,
|
|
||||||
styles = []
|
|
||||||
|
|
||||||
function add_to_string( value, type = null )
|
|
||||||
{
|
|
||||||
if( _colored )
|
|
||||||
{
|
|
||||||
string_tree += '%c'
|
|
||||||
|
|
||||||
switch( type )
|
|
||||||
{
|
|
||||||
case 'structure':
|
|
||||||
styles.push( 'color:#999;' )
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'folder':
|
|
||||||
styles.push( 'color:#999;' )
|
|
||||||
break
|
|
||||||
case 'file':
|
|
||||||
styles.push( 'color:#333;font-weight:bold;' )
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
|
||||||
styles.push( '' )
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string_tree += value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursive describe
|
|
||||||
function describe_folder( folder, depth, last = [] )
|
|
||||||
{
|
|
||||||
// Set up
|
|
||||||
let folder_keys = Object.keys( folder.folders ),
|
|
||||||
file_keys = Object.keys( folder.files )
|
|
||||||
|
|
||||||
// Each folders
|
|
||||||
for( let i = 0; i < folder_keys.length; i++ )
|
|
||||||
{
|
|
||||||
// Set up
|
|
||||||
let _folder_key = folder_keys[ i ],
|
|
||||||
_folder = folder.folders[ _folder_key ]
|
|
||||||
|
|
||||||
// Add to tree string
|
|
||||||
add_to_string( '\n' )
|
|
||||||
|
|
||||||
for( let j = 0; j < depth; j++ )
|
|
||||||
{
|
|
||||||
if( j === depth - 1 )
|
|
||||||
{
|
|
||||||
if( i === folder_keys.length - 1 && file_keys.length === 0 )
|
|
||||||
add_to_string( ' └', 'structure' )
|
|
||||||
else
|
|
||||||
add_to_string( ' ├', 'structure' )
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( last[ j ] )
|
|
||||||
add_to_string( ' ', 'structure' )
|
|
||||||
else
|
|
||||||
add_to_string( ' │', 'structure' )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add_to_string( '─', 'structure' )
|
|
||||||
add_to_string( _folder.name, 'folder' )
|
|
||||||
add_to_string( '/', 'structure' )
|
|
||||||
|
|
||||||
// Last
|
|
||||||
last.push( i === folder_keys.length - 1 && file_keys.length === 0 )
|
|
||||||
|
|
||||||
// Continue
|
|
||||||
describe_folder( _folder, depth + 1, last )
|
|
||||||
}
|
|
||||||
|
|
||||||
// Each files
|
|
||||||
for( let i = 0; i < file_keys.length; i++ )
|
|
||||||
{
|
|
||||||
// Set up
|
|
||||||
let _file_key = file_keys[ i ],
|
|
||||||
_file = folder.files[ _file_key ]
|
|
||||||
|
|
||||||
// Add to tree string
|
|
||||||
string_tree += '\n'
|
|
||||||
|
|
||||||
for( let j = 0; j < depth; j++ )
|
|
||||||
{
|
|
||||||
if( j === depth - 1 )
|
|
||||||
{
|
|
||||||
if( i === file_keys.length - 1 )
|
|
||||||
add_to_string( ' └', 'structure' )
|
|
||||||
else
|
|
||||||
add_to_string( ' ├', 'structure' )
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( last[ j ] )
|
|
||||||
add_to_string( ' ', 'structure' )
|
|
||||||
else
|
|
||||||
add_to_string( ' │', 'structure' )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add_to_string( '─', 'structure' )
|
|
||||||
add_to_string( _file.name, 'file' )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Describe from ./
|
|
||||||
add_to_string( '.', 'folder' )
|
|
||||||
add_to_string( '/', 'structure' )
|
|
||||||
describe_folder( this.folders[ '.' ], depth + 1 )
|
|
||||||
|
|
||||||
// Log
|
|
||||||
if( _log )
|
|
||||||
{
|
|
||||||
console.log.apply(console, [ string_tree ].concat( styles ) )
|
|
||||||
}
|
|
||||||
|
|
||||||
return string_tree
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Tests
|
|
||||||
// */
|
|
||||||
// let tree = new Tree( { auto_wash: false } )
|
|
||||||
|
|
||||||
// tree.add_folder( './hey/hoy', { active: false, notifs: 0 } )
|
|
||||||
// tree.add_folder( './hey/hoy/toto', { active: false, notifs: 0 } )
|
|
||||||
// tree.add_folder( './hey/hoy/tata', { active: false, notifs: 0 } )
|
|
||||||
|
|
||||||
// tree.add_file( './test-1.txt', { active: false, notifs: 0 } )
|
|
||||||
// tree.add_file( './hey/hoy/test-2.txt', { active: false, notifs: 0 } )
|
|
||||||
// tree.add_file( './hey/hoy/test-3.txt', { active: false, notifs: 0 } )
|
|
||||||
// tree.add_file( './hey/hoy/tata/test-4.txt', { active: false, notifs: 0 } )
|
|
||||||
// tree.add_file( './hey/hoy/toto/test-5.txt', { active: false, notifs: 0 } )
|
|
||||||
|
|
||||||
// tree.add_file( './hey/hoy/toto/test-6.txt', { active: false, notifs: 0, on_remove: function( file ){ console.log( 'removed file :', file ); } } )
|
|
||||||
// tree.remove_file( './hey/hoy/toto/test-6.txt' )
|
|
||||||
|
|
||||||
// tree.add_folder( './pwet', { on_remove: function( folder ){ console.log( 'removed folder :', folder ); } } )
|
|
||||||
// tree.add_folder( './pwet/uh', { on_remove: function( folder ){ console.log( 'removed folder :', folder ); } } )
|
|
||||||
// tree.remove_folder( './pwet' )
|
|
||||||
|
|
||||||
// tree.remove_file( './hey/hoy/test-2.txt' )
|
|
||||||
// tree.remove_folder( './hey' )
|
|
||||||
|
|
||||||
// tree.describe( true, true )
|
|
||||||
@@ -16,6 +16,20 @@ application.factory(
|
|||||||
_version.date_formated = _version.moment_date.format( 'LTS' );
|
_version.date_formated = _version.moment_date.format( 'LTS' );
|
||||||
_version.time_from_now = _version.moment_date.fromNow();
|
_version.time_from_now = _version.moment_date.fromNow();
|
||||||
|
|
||||||
|
// Project last update date
|
||||||
|
if( _version.moment_date.isAfter( result.last_update_moment_date ) )
|
||||||
|
{
|
||||||
|
result.last_update_moment_date = _version.moment_date;
|
||||||
|
result.last_update_date_formated = _version.date_formated;
|
||||||
|
result.last_update_time_from_now = _version.time_from_now;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lines
|
||||||
|
_version.lines = [];
|
||||||
|
var length = _version.content.split(/\r\n|\r|\n/).length;
|
||||||
|
for( var i = 1; i < length + 1; i++ )
|
||||||
|
_version.lines.push( i );
|
||||||
|
|
||||||
// Differences
|
// Differences
|
||||||
var count = 0,
|
var count = 0,
|
||||||
modified = 0;
|
modified = 0;
|
||||||
@@ -65,6 +79,7 @@ application.factory(
|
|||||||
'html' : [ 'html', 'htm' ],
|
'html' : [ 'html', 'htm' ],
|
||||||
'sass' : [ 'sass', 'scss' ],
|
'sass' : [ 'sass', 'scss' ],
|
||||||
'less' : [ 'less' ],
|
'less' : [ 'less' ],
|
||||||
|
'stylus' : [ 'stylus', 'styl' ],
|
||||||
'css' : [ 'css' ],
|
'css' : [ 'css' ],
|
||||||
'php' : [ 'php' ],
|
'php' : [ 'php' ],
|
||||||
'json' : [ 'json' ],
|
'json' : [ 'json' ],
|
||||||
@@ -105,7 +120,9 @@ application.factory(
|
|||||||
var result = {};
|
var result = {};
|
||||||
result.name = '';
|
result.name = '';
|
||||||
result.files = {};
|
result.files = {};
|
||||||
result.tree = new Tree( { auto_wash: false } );
|
result.files_count = 0;
|
||||||
|
result.tree = new FileTree( { auto_wash: false } );
|
||||||
|
result.date_formated = '';
|
||||||
result.on_update = null;
|
result.on_update = null;
|
||||||
result.on_new_version = null;
|
result.on_new_version = null;
|
||||||
|
|
||||||
@@ -134,6 +151,8 @@ application.factory(
|
|||||||
result.files[ data.path.full ] = file;
|
result.files[ data.path.full ] = file;
|
||||||
|
|
||||||
result.tree.add_file( data.path.full, file )
|
result.tree.add_file( data.path.full, file )
|
||||||
|
|
||||||
|
result.files_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply callback
|
// Apply callback
|
||||||
@@ -170,6 +189,8 @@ application.factory(
|
|||||||
{
|
{
|
||||||
result.tree.remove_file( file.path.full )
|
result.tree.remove_file( file.path.full )
|
||||||
|
|
||||||
|
result.files_count--;
|
||||||
|
|
||||||
delete result.files[ data.path.full ]
|
delete result.files[ data.path.full ]
|
||||||
|
|
||||||
// Apply callback
|
// Apply callback
|
||||||
@@ -181,7 +202,18 @@ application.factory(
|
|||||||
// Update project event
|
// Update project event
|
||||||
socket.on( 'update_project', function( data )
|
socket.on( 'update_project', function( data )
|
||||||
{
|
{
|
||||||
result.name = data.name;
|
result.name = data.name;
|
||||||
|
result.files_count = data.files.count;
|
||||||
|
|
||||||
|
// Date
|
||||||
|
result.moment_date = moment( data.date );
|
||||||
|
result.date_formated = result.moment_date.format( 'LTS' );
|
||||||
|
result.time_from_now = result.moment_date.fromNow();
|
||||||
|
|
||||||
|
// Last update date
|
||||||
|
result.last_update_moment_date = moment( data.last_update_date );
|
||||||
|
result.last_update_date_formated = result.last_update_moment_date.format( 'LTS' );
|
||||||
|
result.last_update_time_from_now = result.last_update_moment_date.fromNow();
|
||||||
|
|
||||||
// Duplicate files
|
// Duplicate files
|
||||||
for( var _file_key in data.files.items )
|
for( var _file_key in data.files.items )
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ application.factory(
|
|||||||
_project.time_from_now = _project.moment_date.fromNow();
|
_project.time_from_now = _project.moment_date.fromNow();
|
||||||
|
|
||||||
// Last update date
|
// Last update date
|
||||||
_project.moment_date = moment( _project.last_update_date );
|
_project.last_update_moment_date = moment( _project.last_update_date );
|
||||||
_project.last_update_date_formated = _project.moment_date.format( 'LTS' );
|
_project.last_update_date_formated = _project.last_update_moment_date.format( 'LTS' );
|
||||||
_project.last_update_time_from_now = _project.moment_date.fromNow();
|
_project.last_update_time_from_now = _project.last_update_moment_date.fromNow();
|
||||||
|
|
||||||
return _project;
|
return _project;
|
||||||
}
|
}
|
||||||
@@ -32,6 +32,8 @@ application.factory(
|
|||||||
{
|
{
|
||||||
result.data = data;
|
result.data = data;
|
||||||
|
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
for( var _project_key in result.data.all )
|
for( var _project_key in result.data.all )
|
||||||
{
|
{
|
||||||
var project = result.data.all[ _project_key ];
|
var project = result.data.all[ _project_key ];
|
||||||
|
|||||||
@@ -3,6 +3,12 @@ body
|
|||||||
font-size 12px
|
font-size 12px
|
||||||
font-smoothing(antialiased)
|
font-smoothing(antialiased)
|
||||||
|
|
||||||
|
::-moz-selection
|
||||||
|
background #f1eff9
|
||||||
|
::selection
|
||||||
|
background #f1eff9
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ body.project
|
|||||||
padding 12px 20px 0 20px
|
padding 12px 20px 0 20px
|
||||||
border-top 1px solid #515771
|
border-top 1px solid #515771
|
||||||
border-bottom 1px solid #515771
|
border-bottom 1px solid #515771
|
||||||
background rgba(0,0,0,0.2)
|
background #2c2f42
|
||||||
|
|
||||||
.name
|
.name
|
||||||
position absolute
|
position absolute
|
||||||
@@ -90,9 +90,10 @@ body.project
|
|||||||
position absolute
|
position absolute
|
||||||
top 115px
|
top 115px
|
||||||
left 0
|
left 0
|
||||||
width 100%
|
bottom 95px
|
||||||
bottom 110px
|
width calc(100% + 15px)
|
||||||
overflow-y scroll
|
overflow-y scroll
|
||||||
|
overflow-x scroll
|
||||||
|
|
||||||
nav.files-tree-nav
|
nav.files-tree-nav
|
||||||
position absolute
|
position absolute
|
||||||
@@ -104,6 +105,7 @@ body.project
|
|||||||
line-height 24px
|
line-height 24px
|
||||||
font-size 12px
|
font-size 12px
|
||||||
cursor pointer
|
cursor pointer
|
||||||
|
white-space nowrap
|
||||||
|
|
||||||
.name
|
.name
|
||||||
position relative
|
position relative
|
||||||
@@ -132,24 +134,25 @@ body.project
|
|||||||
line-height 13px
|
line-height 13px
|
||||||
|
|
||||||
> span
|
> span
|
||||||
display block
|
display inline-block
|
||||||
padding-left 16px * 1
|
padding-right 20px
|
||||||
|
padding-left 15px * 1
|
||||||
li > span
|
li > span
|
||||||
padding-left 16px * 2
|
padding-left 15px * 2
|
||||||
li li > span
|
li li > span
|
||||||
padding-left 16px * 3
|
padding-left 15px * 3
|
||||||
li li li > span
|
li li li > span
|
||||||
padding-left 16px * 4
|
padding-left 15px * 4
|
||||||
li li li li > span
|
li li li li > span
|
||||||
padding-left 16px * 5
|
padding-left 15px * 5
|
||||||
li li li li li > span
|
li li li li li > span
|
||||||
padding-left 16px * 6
|
padding-left 15px * 6
|
||||||
li li li li li li > span
|
li li li li li li > span
|
||||||
padding-left 16px * 7
|
padding-left 15px * 7
|
||||||
li li li li li li li > span
|
li li li li li li li > span
|
||||||
padding-left 16px * 8
|
padding-left 15px * 8
|
||||||
li li li li li li li li > span
|
li li li li li li li li > span
|
||||||
padding-left 16px * 9
|
padding-left 15px * 9
|
||||||
|
|
||||||
&.active
|
&.active
|
||||||
background #4d5b8d
|
background #4d5b8d
|
||||||
@@ -175,6 +178,8 @@ body.project
|
|||||||
background-image url('../svg/sass.svg')
|
background-image url('../svg/sass.svg')
|
||||||
&.less
|
&.less
|
||||||
background-image url('../svg/less.svg')
|
background-image url('../svg/less.svg')
|
||||||
|
&.stylus
|
||||||
|
background-image url('../svg/stylus.svg')
|
||||||
&.css
|
&.css
|
||||||
background-image url('../svg/css.svg')
|
background-image url('../svg/css.svg')
|
||||||
&.php
|
&.php
|
||||||
@@ -226,12 +231,12 @@ body.project
|
|||||||
left 0
|
left 0
|
||||||
width 100%
|
width 100%
|
||||||
height 110px
|
height 110px
|
||||||
padding 15px 20px 0 20px
|
padding 10px 20px 0 20px
|
||||||
border-top 1px solid #515771
|
border-top 1px solid #515771
|
||||||
background rgba(0,0,0,0.2)
|
background #2c2f42
|
||||||
|
|
||||||
.button-container
|
.button-container
|
||||||
margin-bottom 5px
|
|
||||||
.button
|
.button
|
||||||
&.switch
|
&.switch
|
||||||
display inline-block
|
display inline-block
|
||||||
@@ -279,6 +284,7 @@ body.project
|
|||||||
|
|
||||||
&.default
|
&.default
|
||||||
display inline-block
|
display inline-block
|
||||||
|
margin 10px 0
|
||||||
padding 5px 10px
|
padding 5px 10px
|
||||||
background rgba(128,147,232,0.2)
|
background rgba(128,147,232,0.2)
|
||||||
text-decoration none
|
text-decoration none
|
||||||
@@ -294,6 +300,7 @@ body.project
|
|||||||
left 240px
|
left 240px
|
||||||
right 0
|
right 0
|
||||||
bottom 0
|
bottom 0
|
||||||
|
background #31344a
|
||||||
|
|
||||||
section.no-file
|
section.no-file
|
||||||
position absolute
|
position absolute
|
||||||
@@ -348,10 +355,12 @@ body.project
|
|||||||
position absolute
|
position absolute
|
||||||
top 0
|
top 0
|
||||||
left 0
|
left 0
|
||||||
width 200px
|
|
||||||
bottom 0
|
bottom 0
|
||||||
|
width 215px
|
||||||
|
padding-bottom 5px
|
||||||
background #4d5b8d
|
background #4d5b8d
|
||||||
overflow-y scroll
|
overflow-y scroll
|
||||||
|
overflow-x hidden
|
||||||
|
|
||||||
a.version
|
a.version
|
||||||
display block
|
display block
|
||||||
@@ -438,37 +447,46 @@ body.project
|
|||||||
section.code
|
section.code
|
||||||
position absolute
|
position absolute
|
||||||
top 30px
|
top 30px
|
||||||
right 0
|
right -15px
|
||||||
bottom 0
|
bottom -15px
|
||||||
left 200px
|
left 200px
|
||||||
|
background #31344a
|
||||||
overflow-y scroll
|
overflow-y scroll
|
||||||
|
overflow-x scroll
|
||||||
|
|
||||||
pre
|
pre
|
||||||
position relative
|
position relative
|
||||||
overflow hidden
|
|
||||||
|
|
||||||
code
|
code
|
||||||
line-height 20px
|
line-height 20px
|
||||||
font-family monospace
|
font-family monospace
|
||||||
|
|
||||||
&.lines
|
.lines
|
||||||
position absolute
|
position absolute
|
||||||
top 0
|
top 0
|
||||||
left 0
|
left 0
|
||||||
width 38px
|
width 38px
|
||||||
padding 0.5em
|
padding 0.5em
|
||||||
opacity 0.2
|
opacity 0.2
|
||||||
|
|
||||||
&.hljs
|
.current
|
||||||
|
pre
|
||||||
|
code
|
||||||
|
display inline-block
|
||||||
|
margin-right 15px
|
||||||
|
margin-bottom 15px
|
||||||
margin-left 38px
|
margin-left 38px
|
||||||
background none
|
background none
|
||||||
|
|
||||||
&.differences
|
.differences
|
||||||
position absolute
|
position absolute
|
||||||
top 0
|
top 0
|
||||||
left 38px
|
left 38px
|
||||||
padding 0.5em
|
padding 0.5em
|
||||||
pointer-events none
|
pointer-events none
|
||||||
|
|
||||||
|
pre
|
||||||
|
code
|
||||||
|
|
||||||
.value
|
.value
|
||||||
visibility hidden
|
visibility hidden
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
@import 'nib'
|
||||||
|
|
||||||
@import 'mixins/font-smoothing'
|
@import 'mixins/font-smoothing'
|
||||||
@import 'mixins/rupture'
|
@import 'mixins/rupture'
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="38.8 33.4 138.5 141.4" enable-background="new 38.8 33.4 138.5 141.4" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="#B3D107" d="M170.8,33.4c1.6,0,3,0.4,4,1.2c1,0.8,1.7,1.9,2.1,3.3c0.4,1.4,0.4,2.9,0.2,4.7c-0.3,1.8-0.9,3.5-1.9,5.2
|
||||||
|
c-0.2,0.2-0.5,0.2-0.8,0c-0.3-0.2-0.5-0.5-0.7-0.8c0.2-1.3-0.2-2.4-1.4-3.3c-1.1-0.9-2.9-1.3-5.3-1.3c-4.5,0-9,1.7-13.5,5
|
||||||
|
c-4.5,3.3-8.9,7.7-13.2,13.2c-4.3,5.5-8.3,11.8-12,18.9c-3.7,7.1-6.9,14.4-9.7,22c-2.7,7.5-4.9,15-6.5,22.5
|
||||||
|
c-1.6,7.4-2.4,14.2-2.4,20.3c0,3.3,0.9,4.9,2.8,4.9c1.3,0,2.6-0.5,3.9-1.6c1.3-1.1,2.7-2.7,4.3-4.9c0.3-0.2,0.6-0.2,0.9,0.1
|
||||||
|
c0.3,0.3,0.4,0.6,0.2,1.1c-2.2,3.3-4.8,6-7.7,8.2c-2.9,2.2-5.6,3.3-8,3.3c-2.1,0-3.5-0.6-4.3-1.8c-0.8-1.2-1.2-2.7-1.2-4.6
|
||||||
|
c0-5.1,1.1-11.6,3.3-19.3c2.2-7.7,5.1-15.8,8.8-24.4c3.7-8.6,7.9-17.1,12.7-25.7c4.8-8.5,9.8-16.2,15-23
|
||||||
|
c5.2-6.8,10.4-12.4,15.7-16.6C161.3,35.6,166.2,33.4,170.8,33.4z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#B3D107" d="M45.3,174.9c-1.6,0-3-0.4-4-1.2c-1-0.8-1.7-1.9-2.1-3.3c-0.4-1.4-0.4-2.9-0.2-4.7c0.3-1.8,0.9-3.5,1.9-5.2
|
||||||
|
c0.2-0.2,0.5-0.2,0.8,0c0.3,0.2,0.5,0.5,0.7,0.8c-0.2,1.3,0.2,2.4,1.4,3.3c1.1,0.9,2.9,1.3,5.3,1.3c4.5,0,9-1.7,13.5-5
|
||||||
|
c4.5-3.3,8.9-7.7,13.2-13.2c4.3-5.5,8.3-11.7,12-18.9c3.7-7.1,6.9-14.4,9.7-22c2.7-7.5,4.9-15,6.5-22.5c1.6-7.4,2.4-14.2,2.4-20.3
|
||||||
|
c0-3.3-0.9-4.9-2.8-4.9c-1.3,0-2.6,0.5-3.9,1.6c-1.3,1.1-2.7,2.7-4.3,4.9c-0.3,0.2-0.6,0.2-0.9-0.1c-0.3-0.3-0.4-0.6-0.2-1.1
|
||||||
|
c2.2-3.3,4.8-6,7.7-8.2c2.9-2.2,5.6-3.3,8-3.3c2.1,0,3.5,0.6,4.3,1.8s1.2,2.7,1.2,4.6c0,5.1-1.1,11.6-3.3,19.3
|
||||||
|
c-2.2,7.7-5.1,15.8-8.8,24.4c-3.7,8.6-7.9,17.1-12.7,25.7c-4.8,8.5-9.8,16.2-15,23c-5.2,6.8-10.4,12.4-15.7,16.6
|
||||||
|
C54.8,172.7,49.9,174.9,45.3,174.9z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -41,17 +41,17 @@ div(ng-controller="ProjectController as controller",ng-init="init('" + project_s
|
|||||||
.label
|
.label
|
||||||
| created at
|
| created at
|
||||||
.value
|
.value
|
||||||
| 11:20:13 PM
|
| {{project.date_formated}}
|
||||||
.detail
|
.detail
|
||||||
.label
|
.label
|
||||||
| last update
|
| last update
|
||||||
.value
|
.value
|
||||||
| 11:20:13 PM
|
| {{project.last_update_date_formated}}
|
||||||
.detail
|
.detail
|
||||||
.label
|
.label
|
||||||
| files
|
| files
|
||||||
.value
|
.value
|
||||||
| 32
|
| {{project.files_count}}
|
||||||
|
|
||||||
.aside-tree
|
.aside-tree
|
||||||
nav.files-tree-nav
|
nav.files-tree-nav
|
||||||
@@ -80,12 +80,6 @@ div(ng-controller="ProjectController as controller",ng-init="init('" + project_s
|
|||||||
.text
|
.text
|
||||||
| Choose a file
|
| Choose a file
|
||||||
section.file(ng-if="file")
|
section.file(ng-if="file")
|
||||||
header.file-header
|
|
||||||
.content
|
|
||||||
span.path
|
|
||||||
| {{file.path.directory}}/
|
|
||||||
span.name
|
|
||||||
| {{file.name}}
|
|
||||||
nav.versions-nav
|
nav.versions-nav
|
||||||
a.version(href="#",ng-repeat="_version in file.versions",ng-click="version_click(_version)",ng-class="_version.active ? 'active' : 'inactive'")
|
a.version(href="#",ng-repeat="_version in file.versions",ng-click="version_click(_version)",ng-class="_version.active ? 'active' : 'inactive'")
|
||||||
.background
|
.background
|
||||||
@@ -103,18 +97,24 @@ div(ng-controller="ProjectController as controller",ng-init="init('" + project_s
|
|||||||
.fill(style="width:{{_version.diff_percent}};")
|
.fill(style="width:{{_version.diff_percent}};")
|
||||||
.percent(style="width:{{_version.diff_percent}};")
|
.percent(style="width:{{_version.diff_percent}};")
|
||||||
| {{_version.diff_percent}}
|
| {{_version.diff_percent}}
|
||||||
|
header.file-header
|
||||||
|
.content
|
||||||
|
span.path
|
||||||
|
| {{file.path.directory}}/
|
||||||
|
span.name
|
||||||
|
| {{file.name}}
|
||||||
section.code
|
section.code
|
||||||
pre
|
.lines
|
||||||
code.lines
|
pre
|
||||||
- var line_index = 1
|
code
|
||||||
while line_index < 999
|
.line(ng-repeat="_line in version.lines")
|
||||||
.line= line_index++
|
| {{ _line }}
|
||||||
code(hljs,hljs-source="version.content")
|
.current(hljs,hljs-source="version.content")
|
||||||
| {{ version.content }}
|
.differences
|
||||||
code.differences(ng-if="version.diff",ng-class="show_differences ? 'active' : 'inactive'")
|
pre
|
||||||
span(ng-repeat="_difference in version.diff",ng-class="{removed: _difference.removed, added: _difference.added}")
|
code(ng-if="version.diff",ng-class="show_differences ? 'active' : 'inactive'")
|
||||||
span.value
|
span(ng-repeat="_difference in version.diff",ng-class="{removed: _difference.removed, added: _difference.added}")
|
||||||
| {{ _difference.value }}
|
span.value
|
||||||
|
| {{ _difference.value }}
|
||||||
|
|
||||||
include ../../partials/footer.pug
|
include ../../partials/footer.pug
|
||||||
|
|||||||
@@ -18,7 +18,16 @@ html(ng-app="application")
|
|||||||
script(src="/javascript/controllers/projects.js")
|
script(src="/javascript/controllers/projects.js")
|
||||||
script(src="/javascript/services/project.js")
|
script(src="/javascript/services/project.js")
|
||||||
script(src="/javascript/services/projects.js")
|
script(src="/javascript/services/projects.js")
|
||||||
script(src="/javascript/models/tree.js")
|
script(src="/javascript/models/file_tree.js")
|
||||||
|
|
||||||
|
link(rel="apple-touch-icon", sizes="180x180", href="/images/icons/apple-touch-icon.png")
|
||||||
|
link(rel="icon", type="image/png", href="/images/icons/favicon-32x32.png", sizes="32x32")
|
||||||
|
link(rel="icon", type="image/png", href="/images/icons/favicon-16x16.png", sizes="16x16")
|
||||||
|
link(rel="manifest", href="/images/icons/manifest.json")
|
||||||
|
link(rel="mask-icon", href="/images/icons/safari-pinned-tab.svg", color="#5bbad5")
|
||||||
|
meta(name="apple-mobile-web-app-title", content="Keppler")
|
||||||
|
meta(name="application-name", content="Keppler")
|
||||||
|
meta(name="theme-color", content="#ffffff")
|
||||||
|
|
||||||
link(rel="stylesheet",href="/stylesheet/style.css")
|
link(rel="stylesheet",href="/stylesheet/style.css")
|
||||||
link(rel="stylesheet",href="/vendors/highlight/styles/dracula.css")
|
link(rel="stylesheet",href="/vendors/highlight/styles/dracula.css")
|
||||||
|
|||||||