From 816c164c8c04754561f9cc075208af5100045661 Mon Sep 17 00:00:00 2001 From: brunosimon Date: Thu, 11 Aug 2016 19:21:38 +0200 Subject: [PATCH] Add tree class --- site/app.class.js | 20 +- site/models/event_emitter.class.js | 221 ++++++ site/models/files.class.js | 18 +- site/models/project.class.js | 4 +- site/public/javascript/controllers/project.js | 30 +- site/public/javascript/models/tree.js | 641 ++++++++++++++++++ site/public/javascript/services/project.js | 212 ++---- site/public/stylesheets/style.css | 18 +- site/views/pages/index/project.jade | 6 +- site/views/partials/header.jade | 1 + 10 files changed, 976 insertions(+), 195 deletions(-) create mode 100644 site/models/event_emitter.class.js create mode 100644 site/public/javascript/models/tree.js diff --git a/site/app.class.js b/site/app.class.js index f40c0e2..910060c 100644 --- a/site/app.class.js +++ b/site/app.class.js @@ -49,7 +49,14 @@ class App project.files.update( './toto/tata/lorem.txt', '1aze' ) project.files.update( './toto/tata/ipsum.txt', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Mollitia asperiores iure, animi voluptatibus ut officiis. Molestias, quod perferendis hic totam doloremque, porro aperiam enim tenetur, maxime inventore consequuntur nisi in?' ) project.files.delete( './toto/tata/ipsum.txt' ) - console.log( util.inspect( project.files, { depth: null, colors: true } ) ) + + var counting = 0 + setInterval( function() + { + project.files.update( './coucou/coco.txt', 'test: ' + counting++ ) + }, 2000 ) + + console.log( util.inspect( project.files.describe(), { depth: null, colors: true } ) ) } /** @@ -129,28 +136,29 @@ class App // Create project project = this.projects.create_project( data.name ) - console.log( util.inspect( project.files, { depth: null, colors: true } ) ) + console.log( util.inspect( project.files.describe(), { depth: null, colors: true } ) ) } ) socket.on( 'update_file', ( data ) => { - project.files.file( data.path, data.content ) + console.log(data); + project.files.update( data.path, data.content ) - console.log( util.inspect( project.files, { depth: null, colors: true } ) ) + console.log( util.inspect( project.files.describe(), { depth: null, colors: true } ) ) } ) socket.on( 'create_file', ( data ) => { project.files.create( data.path, data.content ) - console.log( util.inspect( project.files, { depth: null, colors: true } ) ) + console.log( util.inspect( project.files.describe(), { depth: null, colors: true } ) ) } ) socket.on( 'delete_file', ( data ) => { project.files.delete( data.path ) - console.log( util.inspect( project.files, { depth: null, colors: true } ) ) + console.log( util.inspect( project.files.describe(), { depth: null, colors: true } ) ) } ) } ) } diff --git a/site/models/event_emitter.class.js b/site/models/event_emitter.class.js new file mode 100644 index 0000000..eb386b1 --- /dev/null +++ b/site/models/event_emitter.class.js @@ -0,0 +1,221 @@ +'use strict' + +class Event_Emitter +{ + /** + * Constructor + */ + constructor() + { + this.callbacks = {} + this.callbacks.base = {} + } + + /** + * On + */ + on( names, callback ) + { + let that = this; + + // Errors + if( typeof names === 'undefined' || names === '' ) + { + console.warn( 'wrong names' ) + return false + } + + if( typeof callback === 'undefined' ) + { + console.warn( 'wrong callback' ) + return false + } + + // Resolve names + names = this.resolve_names( names ) + + // Each name + names.forEach( function( name ) + { + // Resolve name + name = that.resolve_name( name ) + + // Create namespace if not exist + if( !( that.callbacks[ name.namespace ] instanceof Object ) ) + that.callbacks[ name.namespace ] = {} + + // Create callback if not exist + if( !( that.callbacks[ name.namespace ][ name.value ] instanceof Array ) ) + that.callbacks[ name.namespace ][ name.value ] = [] + + // Add callback + that.callbacks[ name.namespace ][ name.value ].push( callback ) + }) + + return this + } + + /** + * Off + */ + off( names ) + { + let that = this + + // Errors + if( typeof names === 'undefined' || names === '' ) + { + console.warn( 'wrong name' ) + return false + } + + // Resolve names + names = this.resolve_names( names ) + + // Each name + names.forEach( function( name ) + { + // Resolve name + name = that.resolve_name( name ) + + // Remove namespace + if( name.namespace !== 'base' && name.value === '' ) + { + delete that.callbacks[ name.namespace ] + } + + // Remove specific callback in namespace + else + { + // Default + if( name.namespace === 'base' ) + { + // Try to remove from each namespace + for( let namespace in that.callbacks ) + { + if( that.callbacks[ namespace ] instanceof Object && that.callbacks[ namespace ][ name.value ] instanceof Array ) + { + delete that.callbacks[ namespace ][ name.value ] + + // Remove namespace if empty + if( Object.keys(that.callbacks[ namespace ] ).length === 0 ) + delete that.callbacks[ namespace ] + } + } + } + + // Specified namespace + else if( that.callbacks[ name.namespace ] instanceof Object && that.callbacks[ name.namespace ][ name.value ] instanceof Array ) + { + delete that.callbacks[ name.namespace ][ name.value ] + + // Remove namespace if empty + if( Object.keys( that.callbacks[ name.namespace ] ).length === 0 ) + delete that.callbacks[ name.namespace ] + } + } + }) + + return this + } + + /** + * Trigger + */ + trigger( name, args ) + { + // Errors + if( typeof name === 'undefined' || name === '' ) + { + console.warn( 'wrong name' ) + return false + } + + let that = this, + final_result, + result + + // Default args + if( !( args instanceof Array ) ) + args = [] + + // Resolve names (should on have one event) + name = this.resolve_names( name ) + + // Resolve name + name = that.resolve_name( name[ 0 ] ) + + // Default namespace + if( name.namespace === 'base' ) + { + // Try to find callback in each namespace + for( let namespace in that.callbacks ) + { + if( that.callbacks[ namespace ] instanceof Object && that.callbacks[ namespace ][ name.value ] instanceof Array ) + { + that.callbacks[ namespace ][ name.value ].forEach( function( callback ) + { + result = callback.apply( that,args ) + + if( typeof final_result === 'undefined' ) + final_result = result + } ) + } + } + } + + // Specified namespace + else if( this.callbacks[ name.namespace ] instanceof Object ) + { + if( name.value === '' ) + { + console.warn( 'wrong name' ) + return this + } + + that.callbacks[ name.namespace ][ name.value ].forEach( function( callback ) + { + result = callback.apply( that, args ) + + if( typeof final_result === 'undefined' ) + final_result = result + }) + } + + return final_result + } + + /** + * Resolve names + */ + resolve_names( names ) + { + names = names.replace( /[^a-zA-Z0-9 ,\/.]/g, '' ) + names = names.replace( /[,\/]+/g, ' ' ) + names = names.split( ' ' ) + + return names + } + + /** + * Resolve name + */ + resolve_name( name ) + { + let new_name = {}, + + parts = name.split( '.' ) + + new_name.original = name + new_name.value = parts[ 0 ] + new_name.namespace = 'base' // Base namespace + + // Specified namespace + if( parts.length > 1 && parts[ 1 ] !== '' ) + new_name.namespace = parts[ 1 ] + + return new_name + } +} + +module.exports = Event_Emitter diff --git a/site/models/files.class.js b/site/models/files.class.js index 38674cd..d00fea4 100644 --- a/site/models/files.class.js +++ b/site/models/files.class.js @@ -1,14 +1,15 @@ 'use strict' // Dependencies -let paths = require( '../utils/paths.class.js' ), - File = require( './file.class.js' ) +let paths = require( '../utils/paths.class.js' ), + File = require( './file.class.js' ) class Files { - constructor( options ) + constructor( _options ) { - this.items = {} + this.items = {} + this.socket = _options.socket } create( _path, _content ) @@ -34,6 +35,9 @@ class Files // Save this.items[ normalized_path ] = file + // Emit + this.socket.emit( 'create_file', file.describe() ) + return file } @@ -77,6 +81,9 @@ class Files // Create version file.create_version( _content ) + // Emit + this.socket.emit( 'update_file', file.describe() ) + return file } @@ -95,6 +102,9 @@ class Files file.destructor() delete this.items[ normalized_path ] + // Emit + this.socket.emit( 'delete_file', file.describe() ) + return true } diff --git a/site/models/project.class.js b/site/models/project.class.js index ce5bfc8..3ad0903 100644 --- a/site/models/project.class.js +++ b/site/models/project.class.js @@ -10,9 +10,10 @@ class Project { this.name = options.name this.slug = slug( this.name ) - this.files = new Files() this.set_socket( options.socket ) + + this.files = new Files( { socket: this.socket } ) } set_socket( socket ) @@ -26,7 +27,6 @@ class Project { console.log( 'socket projects'.green.bold + ' - ' + 'connect'.cyan + ' - ' + socket.id.cyan ) - console.log(this.describe()); this.socket.emit( 'update_project', this.describe() ) } ) } diff --git a/site/public/javascript/controllers/project.js b/site/public/javascript/controllers/project.js index 8da7749..b707297 100644 --- a/site/public/javascript/controllers/project.js +++ b/site/public/javascript/controllers/project.js @@ -9,28 +9,30 @@ application.controller( // Every 5 seconds $interval( function() { - // Each version - project.each_version( function( version ) - { - // Date - version.time_from_now = version.moment_date.fromNow(); - } ); + // // Each version + // project.each_version( function( version ) + // { + // // Date + // version.time_from_now = version.moment_date.fromNow(); + // } ); }, 5000 ); $scope.folder_click = function( folder ) { - folder.active = !folder.active; + console.log('folder click'); + // folder.active = !folder.active; }; $scope.file_click = function( file ) { - project.each_file( function( file ) - { - file.active = false; - } ); + console.log('file click'); + // project.each_file( function( file ) + // { + // file.active = false; + // } ); - file.active = true; - $scope.file = file; + // file.active = true; + // $scope.file = file; }; $scope.version_click = function( version ) @@ -47,7 +49,7 @@ application.controller( { $scope.$apply( function() { - $scope.project = project.data; + $scope.project = project; } ); } ); diff --git a/site/public/javascript/models/tree.js b/site/public/javascript/models/tree.js new file mode 100644 index 0000000..78d87b7 --- /dev/null +++ b/site/public/javascript/models/tree.js @@ -0,0 +1,641 @@ +'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 ) diff --git a/site/public/javascript/services/project.js b/site/public/javascript/services/project.js index f5c05ba..4ad7c9b 100644 --- a/site/public/javascript/services/project.js +++ b/site/public/javascript/services/project.js @@ -5,114 +5,15 @@ application.factory( '$timeout', function( config, $timeout ) { + // Result + var result = {}; + result.name = ''; + result.files = {}; + result.tree = new Tree( { auto_wash: false } ); + + // Callback var update_callback = null; - function update_folders( folder ) - { - function recursive_folder_report( new_folder, old_folder ) - { - if( typeof old_folder !== 'undefined' && typeof old_folder.active !== 'undefined' ) - new_folder.active = old_folder.active; - - for( var _folder_key in new_folder.folders ) - { - var _new_folder = new_folder.folders[ _folder_key ], - _old_folder = undefined; - - if( old_folder ) - _old_folder = old_folder.folders[ _folder_key ]; - - _new_folder = recursive_folder_report( _new_folder, _old_folder ); - } - - return new_folder; - } - - folder = recursive_folder_report( folder, result.data ); - - result.data.folders = folder.folders; - } - - function update_files( files ) - { - - } - - function delete_file( id ) - { - delete result.data.files[ id ]; - } - - // Result - var result = {}; - result.data = null; - - result.each_folder = function( folder, callback ) - { - // Only callback provided - if( typeof folder === 'function' ) - { - callback = folder; - folder = result.data; - } - - // Apply callback - callback.apply( folder, [ folder ] ); - - // Each folder - for(var _folder_key in folder.folders) - { - var _folder = folder.folders[ _folder_key ]; - - result.each_folder( _folder, callback ); - } - } - - result.each_file = function( folder, callback ) - { - // Only callback provided - if( typeof folder === 'function' ) - { - callback = folder; - folder = result.data; - } - - // Each folder - result.each_folder( folder, function( folder ) - { - // Each file - for(var _file_key in folder.files) - { - var _file = folder.files[ _file_key ]; - - callback.apply( _file, [ _file ] ); - } - } ); - } - - result.each_version = function( folder, callback ) - { - // Only callback provided - if( typeof folder === 'function' ) - { - callback = folder; - folder = result.data; - } - - // Each file - result.each_file( folder, function( file ) - { - // Each version - for(var _version_key in file.versions) - { - var _version = file.versions[ _version_key ]; - - callback.apply( _version, [ _version ] ); - } - } ); - } - - // Update callback result.on_update = function( callback ) { update_callback = callback; @@ -130,73 +31,66 @@ application.factory( console.log('connected'); } ); + socket.on( 'create_file', function( data ) + { + console.log('create_file'); + console.log(data); + } ); + socket.on( 'update_file', function( data ) { - console.log('update_file'); - console.log(data); + // console.log('update_file'); + // console.log(data); + + var existing_file = result.files[ data.path.full ]; + + // Doesn't exist yet + if( typeof existing_file === 'undefined' ) + { + existing_file = Object.assign( {}, data ); + existing_file.notif = 0; + result.files[ _file_key ] = existing_file; + + result.tree.add_file( _file_key, existing_file ) + } + + existing_file.notif++; + + // Apply callback + if( typeof update_callback === 'function' ) + update_callback.apply( this, [ data ] ); } ); socket.on( 'delete_file', function( data ) { console.log('delete_file'); console.log(data); - - delete_file( data ); - } ); - - socket.on( 'update_folders', function( data ) - { - console.log('update_folders'); - console.log(data); - - update_folders( { folders: data } ); } ); // Update project event socket.on( 'update_project', function( data ) { - console.log('update_project'); - console.log(data); + // console.log('update_project'); + // console.log(data); - update_folders( data ); - update_files( data.files ); + // Duplicate files + for( var _file_key in data.files ) + { + var data_file = data.files[ _file_key ], + existing_file = result.files[ _file_key ]; - // // Reformat versions - // result.each_version( data, function( version ) - // { - // // Date - // version.moment_date = moment( version.date ); - // version.date_formated = version.moment_date.format( 'LTS' ); - // version.time_from_now = version.moment_date.fromNow(); + // Doesn't exist yet + if( typeof existing_file === 'undefined' ) + { + existing_file = Object.assign( {}, data_file ); + existing_file.notif = 0; + result.files[ _file_key ] = existing_file; - // // Differencies - // var count = 0, - // modified = 0; + result.tree.add_file( _file_key, existing_file ) + } - // if( !version.diff ) - // { - // version.diff_ratio = 1; - // count = 1; - // modified = 1; - // } - // else - // { - // for( var _diff_key in version.diff ) - // { - // var _diff = version.diff[ _diff_key ]; - // count += _diff.count; - - // if( _diff.added /*|| _diff.removed*/ ) - // modified += _diff.count; - // } - // version.diff_ratio = modified / count; - // } - - // version.diff_percent = Math.round( version.diff_ratio * 100 ) + '%'; - // } ); - - // // Save in results - // result.data = data; + existing_file.notif++; + } // Apply callback if( typeof update_callback === 'function' ) @@ -204,12 +98,6 @@ application.factory( } ); }; - result.data = { - name : '', - folders: {}, - files : {} - }; - return result; } ] diff --git a/site/public/stylesheets/style.css b/site/public/stylesheets/style.css index d9a1b93..a4064d2 100644 --- a/site/public/stylesheets/style.css +++ b/site/public/stylesheets/style.css @@ -38,9 +38,17 @@ section.page-project section.file .code pre code {position:absolute;top:0;right: * Files tree nav */ nav.files-tree-nav {} -nav.files-tree-nav li {padding:0 8px 0 24px;line-height:24px;cursor:pointer;} -nav.files-tree-nav .folder ul {display:none;} -nav.files-tree-nav .folder.active > ul {display:block;} +nav.files-tree-nav li {line-height:24px;cursor:pointer;} +// nav.files-tree-nav .folder ul {display:none;} +// nav.files-tree-nav .folder.active > ul {display:block;} nav.files-tree-nav i {margin:0 6px 0 0;} -nav.files-tree-nav span {color:#ccc;} -nav.files-tree-nav .active span {color:#fff;} \ No newline at end of file +nav.files-tree-nav li > span {display:block;color:#ccc;} +// nav.files-tree-nav .active span {color:#fff;} + + +nav.files-tree-nav li > span {padding-left:16px;} +nav.files-tree-nav li li > span {padding-left:32px;} +nav.files-tree-nav li li li > span {padding-left:48px;} +nav.files-tree-nav li li li li > span {padding-left:64px;} +nav.files-tree-nav li li li li li > span {padding-left:80px;} +nav.files-tree-nav li li li li li li > span {padding-left:86px;} diff --git a/site/views/pages/index/project.jade b/site/views/pages/index/project.jade index 1a278bc..69b866f 100644 --- a/site/views/pages/index/project.jade +++ b/site/views/pages/index/project.jade @@ -9,7 +9,9 @@ script(type="text/ng-template",id="folder_template.html") li.file(ng-repeat="(_key,_file) in _folder.files",ng-class="_file.active ? 'active' : 'inactive'") span(ng-click="file_click(_file)") i.fa.fa-file-text - | {{_key}} + | {{_file.name}} + span.notif + | ({{_file.data.notif}}) section.page-project(ng-controller="ProjectController as controller",ng-init="init('" + project_slug + "')") aside.aside @@ -17,7 +19,7 @@ section.page-project(ng-controller="ProjectController as controller",ng-init="in | {{project.name}} nav.files-tree-nav ul - li.folder(ng-repeat="_folder in project.folders",ng-include="'folder_template.html'",ng-class="_folder.active ? 'active' : 'inactive'") + li.folder(ng-repeat="_folder in project.tree.folders",ng-include="'folder_template.html'",ng-class="_folder.active ? 'active' : 'inactive'") section.file header.file-header | {{file.name}} diff --git a/site/views/partials/header.jade b/site/views/partials/header.jade index 860640a..bc48128 100644 --- a/site/views/partials/header.jade +++ b/site/views/partials/header.jade @@ -19,6 +19,7 @@ html(ng-app="application") script(src="/javascript/controllers/projects.js") script(src="/javascript/services/project.js") script(src="/javascript/services/projects.js") + script(src="/javascript/models/tree.js") link(rel="stylesheet",href="/stylesheets/reset.min.css") link(rel="stylesheet",href="/stylesheets/style.css")