зеркало из https://github.com/mozilla/FlightDeck.git
the removal the huge Package.js
* converted various Files to use Models now
This commit is contained in:
Родитель
5a0584a6ba
Коммит
de89cd75fb
|
@ -16,7 +16,6 @@
|
||||||
<script src="/media/lib/ace/mode-html.js"></script>
|
<script src="/media/lib/ace/mode-html.js"></script>
|
||||||
<script src="/media/lib/meio/Meio.Autocomplete.HTML-1.3.js"></script>
|
<script src="/media/lib/meio/Meio.Autocomplete.HTML-1.3.js"></script>
|
||||||
<script src="/media/base/js/FlightDeck.Autocomplete.js"></script>
|
<script src="/media/base/js/FlightDeck.Autocomplete.js"></script>
|
||||||
<script src="/media/jetpack/js/Package.js"></script>
|
|
||||||
<script src="/media/lib/FloatingTips.js"></script>
|
<script src="/media/lib/FloatingTips.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<script src="/media/lib/ace/mode-html.js"></script>
|
<script src="/media/lib/ace/mode-html.js"></script>
|
||||||
<script src="/media/lib/meio/Meio.Autocomplete.HTML-1.3.js"></script>
|
<script src="/media/lib/meio/Meio.Autocomplete.HTML-1.3.js"></script>
|
||||||
<script src="/media/base/js/FlightDeck.Autocomplete.js"></script>
|
<script src="/media/base/js/FlightDeck.Autocomplete.js"></script>
|
||||||
<script src="/media/jetpack/js/Package.js"></script>
|
|
||||||
<script src="/media/lib/FloatingTips.js"></script>
|
<script src="/media/lib/FloatingTips.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
|
@ -1,325 +0,0 @@
|
||||||
var File = new Class({
|
|
||||||
|
|
||||||
Implements: [Options, Events],
|
|
||||||
|
|
||||||
options: {
|
|
||||||
path: null
|
|
||||||
//events
|
|
||||||
//onDestroy: function() {}
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function(pack, options) {
|
|
||||||
this.pack = pack;
|
|
||||||
this.setOptions(options);
|
|
||||||
},
|
|
||||||
|
|
||||||
getShortName: function() {
|
|
||||||
return this.getFullName().split('/').pop();
|
|
||||||
},
|
|
||||||
|
|
||||||
getFullName: function() {
|
|
||||||
var name = this.options.filename;
|
|
||||||
if(this.options.type) {
|
|
||||||
name += '.' + this.options.type;
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
},
|
|
||||||
|
|
||||||
is_editable: function() {
|
|
||||||
return ['css', 'txt', 'js', 'html'].contains(this.options.type);
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy: function() {
|
|
||||||
if (this.active) {
|
|
||||||
// switch editor!
|
|
||||||
mod = null;
|
|
||||||
// try to switch to first element
|
|
||||||
first = false;
|
|
||||||
Object.each(this.pack.modules, function(mod) {
|
|
||||||
if (!first) {
|
|
||||||
first = true;
|
|
||||||
editor.sidebar.setSelectedFile(mod);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!first) {
|
|
||||||
this.pack.editor.setContent('');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.tab) {
|
|
||||||
this.tab.destroy();
|
|
||||||
|
|
||||||
}
|
|
||||||
this.fireEvent('destroy');
|
|
||||||
},
|
|
||||||
|
|
||||||
setChanged: function(isChanged) {
|
|
||||||
if (this.changed != isChanged) {
|
|
||||||
this.fireEvent(isChanged ? 'change' : 'reset');
|
|
||||||
}
|
|
||||||
this.changed = isChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
File.sanitize = function(name) {
|
|
||||||
return name.replace(/[^a-zA-Z0-9=!@#\$%\^&\(\)\+\-_\/\.]+/g, '-');
|
|
||||||
};
|
|
||||||
|
|
||||||
var Library = new Class({
|
|
||||||
|
|
||||||
Extends: File,
|
|
||||||
|
|
||||||
options: {
|
|
||||||
append: true
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function(pack, options) {
|
|
||||||
this.parent(pack, options);
|
|
||||||
|
|
||||||
this.addEvent('destroy', function(){
|
|
||||||
delete pack.libraries[this.options.id_number];
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
getID: function() {
|
|
||||||
return 'Library-' + this.options.id_number;
|
|
||||||
},
|
|
||||||
|
|
||||||
getShortName: function() {
|
|
||||||
return this.options.full_name;
|
|
||||||
},
|
|
||||||
|
|
||||||
getFullName: function() {
|
|
||||||
return this.getID();
|
|
||||||
},
|
|
||||||
|
|
||||||
storeNewVersion: function(version_data) {
|
|
||||||
this._latest_version = version_data;
|
|
||||||
},
|
|
||||||
|
|
||||||
retrieveNewVersion: function() {
|
|
||||||
return this._latest_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
var Attachment = new Class({
|
|
||||||
|
|
||||||
Extends: File,
|
|
||||||
|
|
||||||
options: {
|
|
||||||
code_trigger_suffix: '_attachment_switch', // id of an element which is used to switch editors
|
|
||||||
code_editor_suffix: '_attachment_textarea', // id of the textarea
|
|
||||||
active: false,
|
|
||||||
type: 'js',
|
|
||||||
append: false,
|
|
||||||
filename: '',
|
|
||||||
readonly: false,
|
|
||||||
counter: 'attachments'
|
|
||||||
},
|
|
||||||
|
|
||||||
is_image: function() {
|
|
||||||
return ['jpg', 'gif', 'png'].contains(this.options.type);
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function(pack, options) {
|
|
||||||
this.parent(pack, options);
|
|
||||||
this.options.path = options.filename + '.' + options.type;
|
|
||||||
// uid for editor items
|
|
||||||
this.uid = this.getEditorID();
|
|
||||||
|
|
||||||
this.addEvent('destroy', function(){
|
|
||||||
delete pack.attachments[this.options.uid];
|
|
||||||
});
|
|
||||||
// create editor
|
|
||||||
pack.editor.registerItem(this);
|
|
||||||
},
|
|
||||||
|
|
||||||
loadContent: function() {
|
|
||||||
var that = this,
|
|
||||||
spinnerEl = $(this.tab);
|
|
||||||
new Request({
|
|
||||||
method: 'get',
|
|
||||||
url: this.options.get_url,
|
|
||||||
useSpinner: !!spinnerEl,
|
|
||||||
spinnerTarget: spinnerEl,
|
|
||||||
spinnerOptions: {
|
|
||||||
img: {
|
|
||||||
'class': 'spinner-img spinner-16'
|
|
||||||
},
|
|
||||||
maskBorder: false
|
|
||||||
},
|
|
||||||
onSuccess: function() {
|
|
||||||
var content = this.response.text || '';
|
|
||||||
that.content = content;
|
|
||||||
that.original_content = content;
|
|
||||||
that.fireEvent('loadcontent', content);
|
|
||||||
}
|
|
||||||
}).send();
|
|
||||||
},
|
|
||||||
|
|
||||||
isLoaded: function() {
|
|
||||||
return this.content != null;
|
|
||||||
},
|
|
||||||
|
|
||||||
getID: function() {
|
|
||||||
return 'Attachment-'+this.uid;
|
|
||||||
},
|
|
||||||
|
|
||||||
getEditorID: function() {
|
|
||||||
return this.options.uid + this.options.code_editor_suffix;
|
|
||||||
},
|
|
||||||
|
|
||||||
reassign: function(options) {
|
|
||||||
// every revision, attachments that have changed get a new `uid`.
|
|
||||||
// since Attachments are currently kept track of via the `uid`,
|
|
||||||
// we must adjust all instances that keep track of this
|
|
||||||
// attachment to use the new id, and any other new options that
|
|
||||||
// comes with it
|
|
||||||
|
|
||||||
var packAttachments = this.pack.attachments,
|
|
||||||
editorItems = this.pack.editor.items,
|
|
||||||
oldUID = this.options.uid;
|
|
||||||
|
|
||||||
delete packAttachments[oldUID];
|
|
||||||
|
|
||||||
this.setOptions(options);
|
|
||||||
this.options.path = options.filename + '.' + options.type;
|
|
||||||
packAttachments[options.uid] = this;
|
|
||||||
|
|
||||||
var editorUID = this.getEditorID();
|
|
||||||
editorItems[editorUID] = editorItems[this.uid];
|
|
||||||
delete editorItems[this.uid];
|
|
||||||
this.uid = editorUID;
|
|
||||||
|
|
||||||
if (options.append) {
|
|
||||||
this.append();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.tab) {
|
|
||||||
this.tab.setLabel(this.getShortName());
|
|
||||||
}
|
|
||||||
this.fireEvent('reassign', this.options.uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
Attachment.exists = function(filename, ext) {
|
|
||||||
return Object.some(fd.item.attachments, function(att) {
|
|
||||||
return (att.options.filename == filename) &&
|
|
||||||
att.options.type == ext;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var Module = new Class({
|
|
||||||
|
|
||||||
Extends: File,
|
|
||||||
|
|
||||||
options: {
|
|
||||||
// data
|
|
||||||
// filename: '',
|
|
||||||
// code: '',
|
|
||||||
// author: '',
|
|
||||||
// DOM
|
|
||||||
code_trigger_suffix: '_switch', // id of an element which is used to switch editors
|
|
||||||
suffix: '_module',
|
|
||||||
readonly: false,
|
|
||||||
main: false,
|
|
||||||
executable: false,
|
|
||||||
active: false,
|
|
||||||
type: 'js',
|
|
||||||
append: false,
|
|
||||||
counter: 'modules'
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function(pack, options) {
|
|
||||||
this.parent(pack, options);
|
|
||||||
this.options.path = this.options.filename + '.' + this.options.type;
|
|
||||||
|
|
||||||
this.addEvent('destroy', function(){
|
|
||||||
delete pack.modules[this.options.filename];
|
|
||||||
});
|
|
||||||
|
|
||||||
// an uid for the editor
|
|
||||||
this.uid = this.options.filename + this.options.suffix;
|
|
||||||
// create editor
|
|
||||||
pack.editor.registerItem(this);
|
|
||||||
},
|
|
||||||
|
|
||||||
loadContent: function() {
|
|
||||||
// load data synchronously
|
|
||||||
var spinnerEl = $(this.tab);
|
|
||||||
new Request.JSON({
|
|
||||||
method: 'get',
|
|
||||||
url: this.options.get_url,
|
|
||||||
useSpinner: !!spinnerEl,
|
|
||||||
spinnerTarget: spinnerEl,
|
|
||||||
spinnerOptions: {
|
|
||||||
img: {
|
|
||||||
'class': 'spinner-img spinner-16'
|
|
||||||
},
|
|
||||||
maskBorder: false
|
|
||||||
},
|
|
||||||
onSuccess: function(mod) {
|
|
||||||
var code = mod.code || '';
|
|
||||||
this.original_content = code;
|
|
||||||
this.content = code;
|
|
||||||
this.fireEvent('loadcontent', code);
|
|
||||||
}.bind(this)
|
|
||||||
}).send();
|
|
||||||
},
|
|
||||||
|
|
||||||
isLoaded: function() {
|
|
||||||
return this.content != null;
|
|
||||||
},
|
|
||||||
|
|
||||||
getID: function() {
|
|
||||||
return 'Module-' + this.options.filename.replace(/\//g, '-');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Module.exists = function(filename) {
|
|
||||||
return Object.some(fd.item.modules, function(mod) {
|
|
||||||
return mod.options.filename == filename;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var Folder = new Class({
|
|
||||||
|
|
||||||
Extends: File,
|
|
||||||
|
|
||||||
options: {
|
|
||||||
root_dir: 'l',
|
|
||||||
name: ''
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function(pack, options) {
|
|
||||||
this.parent(pack, options);
|
|
||||||
|
|
||||||
this.addEvent('destroy', function(){
|
|
||||||
delete pack.folders[this.options.root_dir + '/' +this.options.name];
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
getFullName: function() {
|
|
||||||
return this.options.name;
|
|
||||||
},
|
|
||||||
|
|
||||||
getID: function() {
|
|
||||||
return this.options.root_dir + '-'+
|
|
||||||
this.options.name.replace(/\//g, '-');
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
Folder.ROOT_DIR_LIB = 'l';
|
|
||||||
Folder.ROOT_DIR_DATA = 'd';
|
|
||||||
|
|
||||||
Folder.exists = function(filename, root_dir) {
|
|
||||||
return Object.some(fd.item.folders, function(folder) {
|
|
||||||
return (folder.options.root_dir == root_dir &&
|
|
||||||
folder.options.name == filename);
|
|
||||||
});
|
|
||||||
};
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -41,7 +41,7 @@ module.exports = new Class({
|
||||||
if(file.changed) {
|
if(file.changed) {
|
||||||
fd.showQuestion({
|
fd.showQuestion({
|
||||||
title: 'Lose unsaved changes?',
|
title: 'Lose unsaved changes?',
|
||||||
message: 'The tab "'+file.getShortName()+'" that you are trying to close has unsaved changes.',
|
message: 'The tab "'+file.get('shortName')+'" that you are trying to close has unsaved changes.',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
'type': 'reset',
|
'type': 'reset',
|
||||||
|
@ -83,7 +83,7 @@ module.exports = new Class({
|
||||||
addTab: function(file) {
|
addTab: function(file) {
|
||||||
var controller = this;
|
var controller = this;
|
||||||
var tab = new tabs.Tab(this.tabs, {
|
var tab = new tabs.Tab(this.tabs, {
|
||||||
title: file.getShortName()
|
title: file.get('shortName')
|
||||||
});
|
});
|
||||||
|
|
||||||
function change() {
|
function change() {
|
||||||
|
|
|
@ -19,6 +19,10 @@ module.exports = new Class({
|
||||||
fields: {
|
fields: {
|
||||||
url: fields.TextField(),
|
url: fields.TextField(),
|
||||||
data: fields.TextField()
|
data: fields.TextField()
|
||||||
|
},
|
||||||
|
|
||||||
|
uid: function uid() {
|
||||||
|
return this.get('pk');
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
var Class = require('shipyard/class/Class'),
|
var Class = require('shipyard/class/Class'),
|
||||||
Model = require('shipyard/model/Model'),
|
Model = require('shipyard/model/Model'),
|
||||||
fields = require('shipyard/model/fields'),
|
fields = require('shipyard/model/fields'),
|
||||||
Syncable = require('shipyard/sync/Syncable');
|
Syncable = require('shipyard/sync/Syncable'),
|
||||||
|
Request = require('shipyard/http/Request'),
|
||||||
|
string = require('shipyard/utils/string');
|
||||||
|
|
||||||
var File = module.exports = new Class({
|
var File = module.exports = new Class({
|
||||||
|
|
||||||
|
@ -14,7 +16,12 @@ var File = module.exports = new Class({
|
||||||
id: fields.NumberField(),
|
id: fields.NumberField(),
|
||||||
filename: fields.TextField({ required: true }),
|
filename: fields.TextField({ required: true }),
|
||||||
ext: fields.TextField({ 'default': 'js' }),
|
ext: fields.TextField({ 'default': 'js' }),
|
||||||
content: fields.TextField()
|
content: fields.TextField(),
|
||||||
|
main: fields.BooleanField({ 'default': false, write: false }),
|
||||||
|
readonly: fields.BooleanField({ 'default': false, write: false }),
|
||||||
|
|
||||||
|
url: fields.TextField({ write: false }),
|
||||||
|
get_url: fields.TextField({ write: false })
|
||||||
},
|
},
|
||||||
|
|
||||||
shortName: function() {
|
shortName: function() {
|
||||||
|
@ -32,10 +39,63 @@ var File = module.exports = new Class({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
uid: function() {
|
||||||
|
//TODO: this should be the unique hash from the new API
|
||||||
|
return this._uid || (this._uid = string.uniqueID());
|
||||||
|
},
|
||||||
|
|
||||||
isEditable: function() {
|
isEditable: function() {
|
||||||
return this.constructor.EDITABLE_EXTS.indexOf(this.get('ext')) !== -1;
|
return this.constructor.EDITABLE_EXTS.indexOf(this.get('ext')) !== -1;
|
||||||
|
},
|
||||||
|
|
||||||
|
//TODO: Shipyard Models should probably has a isDirty API
|
||||||
|
setChanged: function(isChanged) {
|
||||||
|
this.changed = isChanged;
|
||||||
|
if (isChanged) {
|
||||||
|
this.fireEvent('change');
|
||||||
|
} else {
|
||||||
|
this.fireEvent('reset');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
loadContent: function(callback) {
|
||||||
|
var file = this;
|
||||||
|
var spinnerEl;
|
||||||
|
return new Request({
|
||||||
|
method: 'get',
|
||||||
|
url: this.get('get_url'),
|
||||||
|
useSpinner: !!spinnerEl,
|
||||||
|
spinnerTarget: spinnerEl,
|
||||||
|
spinnerOptions: {
|
||||||
|
img: {
|
||||||
|
'class': 'spinner-img spinner-16'
|
||||||
|
},
|
||||||
|
maskBorder: false
|
||||||
|
},
|
||||||
|
onSuccess: function(text) {
|
||||||
|
var content = text || '';
|
||||||
|
file.original_content = content;
|
||||||
|
file.set('content', content);
|
||||||
|
file.fireEvent('loadcontent', content);
|
||||||
|
if (callback) callback.call(this, content);
|
||||||
|
}
|
||||||
|
}).send();
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
isLoaded: function() {
|
||||||
|
return this.get('content') != null;
|
||||||
|
},
|
||||||
|
|
||||||
|
toString: function() {
|
||||||
|
return this.get('fullName');
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
File.EDITABLE_EXTS = ['js', 'html', 'css', 'txt', 'json', 'md'];
|
File.EDITABLE_EXTS = ['js', 'html', 'css', 'txt', 'json', 'md'];
|
||||||
|
|
||||||
|
var sanitizeRE = /[^a-zA-Z0-9=!@#\$%\^&\(\)\+\-_\/\.]+/g;
|
||||||
|
File.sanitize = function(name) {
|
||||||
|
return name.replace(sanitizeRE, '-');
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
var Class = require('shipyard/class/Class'),
|
||||||
|
Model = require('shipyard/model/Model'),
|
||||||
|
fields = require('shipyard/model/fields'),
|
||||||
|
Syncable = require('shipyard/sync/Syncable'),
|
||||||
|
string = require('shipyard/utils/string');
|
||||||
|
|
||||||
|
var Folder = module.exports = new Class({
|
||||||
|
|
||||||
|
Extends: Model,
|
||||||
|
|
||||||
|
Implements: Syncable,
|
||||||
|
|
||||||
|
fields: {
|
||||||
|
name: fields.TextField({ required: true }),
|
||||||
|
root_dir: fields.TextField({ required: true }) //ChoiceField
|
||||||
|
},
|
||||||
|
|
||||||
|
shortName: function() {
|
||||||
|
return this.get('name');
|
||||||
|
},
|
||||||
|
|
||||||
|
fullName: function() {
|
||||||
|
return this.get('name');
|
||||||
|
},
|
||||||
|
|
||||||
|
uid: function() {
|
||||||
|
return this.get('root_dir') + '/' + this.get('name');
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
Folder.ROOT_DIR_LIB = 'l';
|
||||||
|
Folder.ROOT_DIR_DATA = 'd';
|
|
@ -1,7 +1,8 @@
|
||||||
var Class = require('shipyard/class/Class'),
|
var Class = require('shipyard/class/Class'),
|
||||||
File = require('./File'),
|
File = require('./File'),
|
||||||
fields = require('shipyard/model/fields'),
|
fields = require('shipyard/model/fields'),
|
||||||
ServerSync = require('shipyard/sync/Server');
|
ServerSync = require('shipyard/sync/Server'),
|
||||||
|
Request = require('shipyard/http/Request');
|
||||||
|
|
||||||
module.exports = new Class({
|
module.exports = new Class({
|
||||||
|
|
||||||
|
@ -15,6 +16,35 @@ module.exports = new Class({
|
||||||
},
|
},
|
||||||
|
|
||||||
fields: {
|
fields: {
|
||||||
}
|
},
|
||||||
|
|
||||||
|
uid: function() {
|
||||||
|
return this.get('filename');
|
||||||
|
},
|
||||||
|
|
||||||
|
loadContent: function(callback) {
|
||||||
|
var spinnerEl,
|
||||||
|
file = this;
|
||||||
|
return new Request({
|
||||||
|
method: 'get',
|
||||||
|
url: this.get('get_url'),
|
||||||
|
useSpinner: !!spinnerEl,
|
||||||
|
spinnerTarget: spinnerEl,
|
||||||
|
spinnerOptions: {
|
||||||
|
img: {
|
||||||
|
'class': 'spinner-img spinner-16'
|
||||||
|
},
|
||||||
|
maskBorder: false
|
||||||
|
},
|
||||||
|
onSuccess: function(text) {
|
||||||
|
var mod = JSON.parse(text);
|
||||||
|
var code = mod.code || '';
|
||||||
|
this.original_content = code;
|
||||||
|
this.set('content', code);
|
||||||
|
this.fireEvent('loadcontent', code);
|
||||||
|
if (callback) callback.call(this, code);
|
||||||
|
}.bind(this)
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,13 +32,33 @@ var Package = module.exports = new Class({
|
||||||
version_name: fields.TextField(),
|
version_name: fields.TextField(),
|
||||||
revision_number: fields.NumberField(),
|
revision_number: fields.NumberField(),
|
||||||
|
|
||||||
latest: fields.NumberField(), // a FK to PackageRevision
|
latest: fields.NumberField() // a FK to PackageRevision
|
||||||
|
|
||||||
// modules: FK from Module
|
// modules: FK from Module
|
||||||
// attachments: FK from Attachment
|
// attachments: FK from Attachment
|
||||||
// dependencies: ManyToManyField('self')
|
// dependencies: ManyToManyField('self')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
uid: function() {
|
||||||
|
return this.get('id_number');
|
||||||
|
},
|
||||||
|
|
||||||
|
shortName: function() {
|
||||||
|
return this.get('name');
|
||||||
|
},
|
||||||
|
|
||||||
|
fullName: function() {
|
||||||
|
return this.get('full_name');
|
||||||
|
},
|
||||||
|
|
||||||
|
storeNewVersion: function(version_data) {
|
||||||
|
this._latest_version = version_data;
|
||||||
|
},
|
||||||
|
|
||||||
|
retrieveNewVersion: function() {
|
||||||
|
return this._latest_version;
|
||||||
|
},
|
||||||
|
|
||||||
isAddon: function isAddon() {
|
isAddon: function isAddon() {
|
||||||
return this.get('type') === this.constructor.TYPE_ADDON;
|
return this.get('type') === this.constructor.TYPE_ADDON;
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
"shipyard": {
|
"shipyard": {
|
||||||
"app": "./",
|
"app": "./",
|
||||||
"mini_require": true,
|
"mini_require": true,
|
||||||
"min": "../editor-min.js",
|
"target": "../editor-min.js",
|
||||||
|
"min": false,
|
||||||
|
|
||||||
"test": "./tests"
|
"test": "./tests"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
var File = require('../../models/File');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
'File.sanitize': function(it, setup) {
|
||||||
|
it('should clean out unwanted characters', function(expect) {
|
||||||
|
var val = File.sanitize('<script>window.open()');
|
||||||
|
expect(val).toBe('-script-window.open()');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not strip plus characters', function(expect) {
|
||||||
|
var val = File.sanitize('unload+');
|
||||||
|
expect(val).toBe('unload+');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,4 +1,6 @@
|
||||||
var Module = require('../../models/Module');
|
var Module = require('../../models/Module'),
|
||||||
|
mockXHR = require('shipyard/test/mockXHR'),
|
||||||
|
Spy = require('shipyard/test/Spy');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
'Module': function(it, setup) {
|
'Module': function(it, setup) {
|
||||||
|
@ -14,6 +16,19 @@ module.exports = {
|
||||||
|
|
||||||
m.set('filename', 'events/key.down');
|
m.set('filename', 'events/key.down');
|
||||||
expect(m.get('shortName')).toBe('key.down.js');
|
expect(m.get('shortName')).toBe('key.down.js');
|
||||||
})
|
});
|
||||||
|
|
||||||
|
it('should be able to loadContent', function(expect) {
|
||||||
|
mockXHR('test content');
|
||||||
|
var m = new Module();
|
||||||
|
var fn = new Spy;
|
||||||
|
m.addEvent('loadcontent', fn);
|
||||||
|
m.loadContent(function(content) {
|
||||||
|
expect(content).toBe('test content');
|
||||||
|
expect(m.get('content')).toBe('test content');
|
||||||
|
expect(fn.getCallCount()).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
*/
|
*/
|
||||||
var Class = require('shipyard/class/Class'),
|
var Class = require('shipyard/class/Class'),
|
||||||
Events = require('shipyard/class/Events'),
|
Events = require('shipyard/class/Events'),
|
||||||
Options = require('shipyard/class/Options')
|
Options = require('shipyard/class/Options'),
|
||||||
object = require('shipyard/utils/object');
|
object = require('shipyard/utils/object');
|
||||||
|
|
||||||
// globals: Element, Spinner, Element.addVolatileEvent, fd
|
// globals: Element, Spinner, fd
|
||||||
|
|
||||||
var FDEditor = module.exports = new Class({
|
var FDEditor = module.exports = new Class({
|
||||||
|
|
||||||
|
@ -45,8 +45,8 @@ var FDEditor = module.exports = new Class({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
registerItem: function(item){
|
registerItem: function(uid, item){
|
||||||
this.items[item.uid] = item;
|
this.items[uid] = item;
|
||||||
},
|
},
|
||||||
|
|
||||||
getItem: function(uid){
|
getItem: function(uid){
|
||||||
|
@ -62,38 +62,39 @@ var FDEditor = module.exports = new Class({
|
||||||
|
|
||||||
activateItem: function(item){
|
activateItem: function(item){
|
||||||
// activate load and hook events
|
// activate load and hook events
|
||||||
|
var editor = this;
|
||||||
this.current = item;
|
this.current = item;
|
||||||
this.current.active = true;
|
this.current.active = true;
|
||||||
if (!this.current.isLoaded()) {
|
if (!this.current.isLoaded()) {
|
||||||
this.spinner.show();
|
this.spinner.show();
|
||||||
this.setContent('', true);
|
this.setContent('', true);
|
||||||
this.current.addVolatileEvent('loadcontent', function(content) {
|
this.current.loadContent(function(content) {
|
||||||
//if item == this.current still
|
if (item == editor.current) {
|
||||||
if (item == this.current) {
|
editor.setContent(content);
|
||||||
this.setContent(content);
|
editor.spinner.hide();
|
||||||
this.spinner.hide();
|
|
||||||
}
|
}
|
||||||
//else another file has become active
|
//else another file has become active
|
||||||
}.bind(this));
|
});
|
||||||
this.current.loadContent();
|
|
||||||
} else {
|
} else {
|
||||||
this.setContent(this.current.content);
|
this.setContent(this.current.get('content'));
|
||||||
this.spinner.hide();
|
this.spinner.hide();
|
||||||
}
|
}
|
||||||
if (this.current.options.readonly) {
|
if (this.current.get('readonly')) {
|
||||||
this.setReadOnly();
|
this.setReadOnly();
|
||||||
} else {
|
} else {
|
||||||
this.setEditable();
|
this.setEditable();
|
||||||
}
|
}
|
||||||
this.setSyntax(this.current.options.type);
|
this.setSyntax(this.current.get('ext'));
|
||||||
},
|
},
|
||||||
|
|
||||||
switchTo: function(item){
|
switchTo: function(uid){
|
||||||
$log('FD: DEBUG: FDEditor.switchTo ' + item.uid);
|
$log('FD: DEBUG: FDEditor.switchTo ' + uid);
|
||||||
var self = this;
|
var self = this;
|
||||||
this.switching = true;
|
this.switching = true;
|
||||||
if (!this.getItem(item.uid)) {
|
var item = this.getItem(uid);
|
||||||
this.registerItem(item);
|
if (!item) {
|
||||||
|
//this.registerItem(item);
|
||||||
|
$log('no item wtf');
|
||||||
}
|
}
|
||||||
if (this.current) {
|
if (this.current) {
|
||||||
this.deactivateCurrent();
|
this.deactivateCurrent();
|
||||||
|
@ -103,7 +104,7 @@ var FDEditor = module.exports = new Class({
|
||||||
},
|
},
|
||||||
|
|
||||||
dumpCurrent: function() {
|
dumpCurrent: function() {
|
||||||
this.current.content = this.getContent();
|
this.current.set('content', this.getContent());
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -126,13 +127,13 @@ var FDEditor = module.exports = new Class({
|
||||||
item.setChanged(false);
|
item.setChanged(false);
|
||||||
item.change_hooked = false;
|
item.change_hooked = false;
|
||||||
// refresh original content
|
// refresh original content
|
||||||
item.original_content = item.content;
|
item.original_content = item.get('content');
|
||||||
});
|
});
|
||||||
this.hookChangeIfNeeded();
|
this.hookChangeIfNeeded();
|
||||||
},
|
},
|
||||||
|
|
||||||
hookChangeIfNeeded: function() {
|
hookChangeIfNeeded: function() {
|
||||||
if (!this.current.options.readonly) {
|
if (!this.current.get('readonly')) {
|
||||||
if (!this.current.changed && !this.change_hooked) {
|
if (!this.current.changed && !this.change_hooked) {
|
||||||
this.hookChange();
|
this.hookChange();
|
||||||
} else if (this.current.changed && this.change_hooked) {
|
} else if (this.current.changed && this.change_hooked) {
|
||||||
|
@ -156,8 +157,8 @@ var FDEditor = module.exports = new Class({
|
||||||
if (!this.switching && this.getContent() != this.current.original_content) {
|
if (!this.switching && this.getContent() != this.current.original_content) {
|
||||||
this.current.setChanged(true);
|
this.current.setChanged(true);
|
||||||
this.fireEvent('change');
|
this.fireEvent('change');
|
||||||
$log('FD: DEBUG: changed, code is considered dirty and will remain'
|
$log('DEBUG: changed, code is considered dirty and will remain'+
|
||||||
+'be treated as such even if changes are reverted');
|
'be treated as such even if changes are reverted');
|
||||||
this.unhookChange();
|
this.unhookChange();
|
||||||
} else if (!this.switching && this.current.changed) {
|
} else if (!this.switching && this.current.changed) {
|
||||||
this.current.setChanged(false);
|
this.current.setChanged(false);
|
||||||
|
|
|
@ -1,348 +1,355 @@
|
||||||
var /*Class = require('shipyard/class'),
|
var /*Class = require('shipyard/class'),
|
||||||
shipyard/class only lets Class extends from other shipyard/class,
|
shipyard/class only lets Class extends from other shipyard/class,
|
||||||
and FileTree extends from Tree (which is a regular Moo Class)
|
and FileTree extends from Tree (which is a regular Moo Class)
|
||||||
*/
|
*/
|
||||||
object = require('shipyard/utils/object');
|
object = require('shipyard/utils/object'),
|
||||||
|
|
||||||
|
Module = require('../models/Module'),
|
||||||
|
Attachment = require('../models/Attachment');
|
||||||
|
|
||||||
// globals: Class, Tree, Collapse.LocalStorage, Element, String.implement
|
// globals: Class, Tree, Collapse.LocalStorage, Element, String.implement
|
||||||
|
|
||||||
var FileTree = module.exports = new Class({
|
var FileTree = module.exports = new Class({
|
||||||
|
|
||||||
Extends: Tree,
|
Extends: Tree,
|
||||||
|
|
||||||
options: {
|
options: {
|
||||||
branch: {
|
branch: {
|
||||||
'rel': 'file',
|
'rel': 'file',
|
||||||
'title': 'Untitled',
|
'title': 'Untitled',
|
||||||
'id': null,
|
'id': null,
|
||||||
'class': ''
|
'class': ''
|
||||||
},
|
},
|
||||||
editable: true,
|
editable: true,
|
||||||
actions: {
|
actions: {
|
||||||
//add: false,
|
//add: false,
|
||||||
//edit: false,
|
//edit: false,
|
||||||
//remove: false
|
//remove: false
|
||||||
},
|
},
|
||||||
snap: 3,
|
snap: 3,
|
||||||
id_prefix: '',
|
id_prefix: '',
|
||||||
|
|
||||||
// if container is null, container will default to the Tree el
|
// if container is null, container will default to the Tree el
|
||||||
// "false" will cancel the container
|
// "false" will cancel the container
|
||||||
container: true,
|
container: true
|
||||||
//onAddBranch: function(el, attributes, target){}
|
//onAddBranch: function(el, attributes, target){}
|
||||||
//onRenameStart: function(li, span){}
|
//onRenameStart: function(li, span){}
|
||||||
//onRenameComplete: function(li, span){}
|
//onRenameComplete: function(li, span){}
|
||||||
//onDeleteBranch: function(li, span){}
|
//onDeleteBranch: function(li, span){}
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize: function(element, options) {
|
initialize: function(element, options) {
|
||||||
this.addEvent('change', function() {
|
this.addEvent('change', function() {
|
||||||
this.setFullPath(this.current);
|
this.setFullPath(this.current);
|
||||||
}, true);
|
}, true);
|
||||||
this.parent(element, options);
|
this.parent(element, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
attach: function(){
|
attach: function(){
|
||||||
this.parent();
|
this.parent();
|
||||||
var that = this;
|
var that = this;
|
||||||
this.element.addEvents({
|
this.element.addEvents({
|
||||||
'mousedown:relay(.actions .edit)': function(e) {
|
'mousedown:relay(.actions .edit)': function(e) {
|
||||||
var li = e.target.getParent('li');
|
var li = e.target.getParent('li');
|
||||||
if (li.hasClass('editing')) {
|
if (li.hasClass('editing')) {
|
||||||
that.renameBranchEnd($(e.target).getParent('li'));
|
that.renameBranchEnd($(e.target).getParent('li'));
|
||||||
} else {
|
} else {
|
||||||
that.renameBranch($(e.target).getParent('li'));
|
that.renameBranch($(e.target).getParent('li'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
'click:relay(li[rel="directory"] > .holder .label, li[rel="directory"] > .holder .icon)': function(e, labelEl){
|
'click:relay(li[rel="directory"] > .holder .label, li[rel="directory"] > .holder .icon)': function(e, labelEl){
|
||||||
var li = e.target.getParent('li');
|
var li = e.target.getParent('li');
|
||||||
that.toggleBranch(li);
|
that.toggleBranch(li);
|
||||||
},
|
},
|
||||||
'keypress:relay(span)': function(e){
|
'keypress:relay(span)': function(e){
|
||||||
if(e.key == 'enter') that.renameBranchEnd($(e.target).getParent('li'));
|
if(e.key == 'enter') that.renameBranchEnd($(e.target).getParent('li'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
mousedown: function(element, event) {
|
mousedown: function(element, event) {
|
||||||
//tree.js prevents event immediately, when really we only want
|
//tree.js prevents event immediately, when really we only want
|
||||||
//the event prevents when it drags. This is because if the element
|
//the event prevents when it drags. This is because if the element
|
||||||
//has contentEditable active, we want the default mousedown action,
|
//has contentEditable active, we want the default mousedown action,
|
||||||
//which is to move the cursor around the text node. If it's not,
|
//which is to move the cursor around the text node. If it's not,
|
||||||
//then preventDefault will be called twice, and the dragging will still
|
//then preventDefault will be called twice, and the dragging will still
|
||||||
//work. :)
|
//work. :)
|
||||||
|
|
||||||
var oldDefault = event.preventDefault;
|
var oldDefault = event.preventDefault;
|
||||||
event.preventDefault = function(){
|
event.preventDefault = function(){
|
||||||
event.preventDefault = oldDefault;
|
event.preventDefault = oldDefault;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.parent(element, event);
|
this.parent(element, event);
|
||||||
if (this.clone) {
|
if (this.clone) {
|
||||||
this.clone.setStyle('display', 'none');
|
this.clone.setStyle('display', 'none');
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
onDrag: function(el, event) {
|
onDrag: function(el, event) {
|
||||||
this.parent(el, event);
|
this.parent(el, event);
|
||||||
if (this.clone) {
|
if (this.clone) {
|
||||||
this.clone.setStyle('display', null); //default snap is already 6px
|
this.clone.setStyle('display', null); //default snap is already 6px
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleBranch: function(branch) {
|
toggleBranch: function(branch) {
|
||||||
if (branch && this.collapse) {
|
if (branch && this.collapse) {
|
||||||
this.collapse.toggle(branch);
|
this.collapse.toggle(branch);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
removeBranch: function(branch) {
|
removeBranch: function(branch) {
|
||||||
var parent = branch.getParent('li');
|
var parent = branch.getParent('li');
|
||||||
|
|
||||||
branch.dispose();
|
branch.dispose();
|
||||||
|
|
||||||
if (parent && !parent.getElements('li').length && this.collapse) {
|
if (parent && !parent.getElements('li').length && this.collapse) {
|
||||||
this.collapse.collapse(parent);
|
this.collapse.collapse(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addBranch: function(attr, target, options){
|
addBranch: function(attr, target, options){
|
||||||
attr = object.merge({}, this.options.branch, attr);
|
attr = object.merge({}, this.options.branch, attr);
|
||||||
target = $(target) || this.element;
|
target = $(target) || this.element;
|
||||||
if (target.get('tag') !== 'ul') {
|
if (target.get('tag') !== 'ul') {
|
||||||
target = target.getElement('ul');
|
target = target.getElement('ul');
|
||||||
}
|
}
|
||||||
|
|
||||||
var isEditable = this.options.editable;
|
var isEditable = this.options.editable;
|
||||||
|
|
||||||
options = object.merge({}, {
|
options = object.merge({}, {
|
||||||
add: attr.rel == 'directory',
|
add: attr.rel == 'directory',
|
||||||
edit: attr.rel != 'directory',
|
edit: attr.rel != 'directory',
|
||||||
remove: true, //can delete anything
|
remove: true, //can delete anything
|
||||||
collapsed: true
|
collapsed: true
|
||||||
}, this.options.actions, options);
|
}, this.options.actions, options);
|
||||||
|
|
||||||
if (!isEditable) {
|
if (!isEditable) {
|
||||||
delete options.add;
|
delete options.add;
|
||||||
delete options.edit;
|
delete options.edit;
|
||||||
delete options.remove;
|
delete options.remove;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr.html = ('<a class="expand" href="#"></a>' +
|
attr.html = ('<a class="expand" href="#"></a>' +
|
||||||
'<div class="holder">' +
|
'<div class="holder">' +
|
||||||
'<span id="{id}" class="label" title="{title}">{title}</span><span class="icon"></span>' +
|
'<span id="{id}" class="label" title="{title}">{title}</span><span class="icon"></span>' +
|
||||||
'<div class="actions">{add}{edit}{remove}</div>' +
|
'<div class="actions">{add}{edit}{remove}</div>' +
|
||||||
'</div>{dir}').substitute({
|
'</div>{dir}').substitute({
|
||||||
title: attr.title,
|
title: attr.title,
|
||||||
id: attr.name ? attr.name + '_switch' : attr.title + '_folder',
|
id: attr.name ? attr.name + '_switch' : attr.title + '_folder',
|
||||||
dir: attr.rel == 'directory' ? '<ul' + (options.collapsed ? ' style="display:none;"' : '') + '></ul>' : '',
|
dir: attr.rel == 'directory' ? '<ul' + (options.collapsed ? ' style="display:none;"' : '') + '></ul>' : '',
|
||||||
add: options.add ? '<span class="add" title="Add"></span>' : '',
|
add: options.add ? '<span class="add" title="Add"></span>' : '',
|
||||||
edit: options.edit ? '<span class="edit" title="Rename"></span>' : '',
|
edit: options.edit ? '<span class="edit" title="Rename"></span>' : '',
|
||||||
remove: options.remove ? '<span class="delete" title="Delete"></span>' : ''
|
remove: options.remove ? '<span class="delete" title="Delete"></span>' : ''
|
||||||
});
|
});
|
||||||
|
|
||||||
var li = new Element('li', attr),
|
var li = new Element('li', attr),
|
||||||
where = 'bottom';
|
where = 'bottom';
|
||||||
|
|
||||||
//branches should always be in alpha order
|
//branches should always be in alpha order
|
||||||
//so, find the place to inject the new branch
|
//so, find the place to inject the new branch
|
||||||
target.getChildren('li').some(function(el) {
|
target.getChildren('li').some(function(el) {
|
||||||
if (el.get('title') > attr.title) {
|
if (el.get('title') > attr.title) {
|
||||||
target = el;
|
target = el;
|
||||||
where = 'before';
|
where = 'before';
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
li.inject(target, where);
|
li.inject(target, where);
|
||||||
this.fireEvent('addBranch', [li].combine(arguments));
|
this.fireEvent('addBranch', [li].combine(arguments));
|
||||||
return li;
|
return li;
|
||||||
},
|
},
|
||||||
|
|
||||||
renameBranch: function(element, hasExtension){
|
renameBranch: function(element, hasExtension){
|
||||||
var li = (element.get('tag') == 'li') ? element : element.getParent('li'),
|
|
||||||
label = li.getElement('.label'),
|
|
||||||
text = label.get('text').trim();
|
|
||||||
|
|
||||||
this.fireEvent('renameStart', [li, label]);
|
|
||||||
|
|
||||||
|
|
||||||
label.set('tabIndex', 0).set('contenteditable', true).focus();
|
|
||||||
li.addClass('editing');
|
|
||||||
label.store('$text', text);
|
|
||||||
|
|
||||||
label.store('$blur', function blur(e) {
|
|
||||||
label.removeEvent('blur', blur);
|
|
||||||
this.renameBranchCancel(element);
|
|
||||||
}.bind(this))
|
|
||||||
|
|
||||||
label.addEvent('blur', label.retrieve('$blur'))
|
|
||||||
|
|
||||||
hasExtension = hasExtension || !!text.getFileExtension();
|
|
||||||
|
|
||||||
var range = document.createRange(),
|
|
||||||
node = label.firstChild;
|
|
||||||
range.setStart(node, 0);
|
|
||||||
range.setEnd(node, hasExtension ? text.length - text.getFileExtension().length -1 : text.length);
|
|
||||||
sel = window.getSelection();
|
|
||||||
sel.removeAllRanges();
|
|
||||||
sel.addRange(range);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
renameBranchCancel: function(element) {
|
|
||||||
var li = (element.get('tag') == 'li') ? element : element.getParent('li'),
|
var li = (element.get('tag') == 'li') ? element : element.getParent('li'),
|
||||||
label = li.getElement('.label'),
|
label = li.getElement('.label'),
|
||||||
text = label.retrieve('$text').trim();
|
text = label.get('text').trim();
|
||||||
|
|
||||||
label.set('contenteditable', false);
|
this.fireEvent('renameStart', [li, label]);
|
||||||
if (text) {
|
|
||||||
label.set('text', text);
|
|
||||||
}
|
label.set('tabIndex', 0).set('contenteditable', true).focus();
|
||||||
label.eliminate('$text');
|
li.addClass('editing');
|
||||||
li.removeClass('editing');
|
label.store('$text', text);
|
||||||
|
|
||||||
},
|
label.store('$blur', function blur(e) {
|
||||||
|
label.removeEvent('blur', blur);
|
||||||
renameBranchEnd: function(element) {
|
this.renameBranchCancel(element);
|
||||||
var li = (element.get('tag') == 'li') ? element : element.getParent('li'),
|
}.bind(this));
|
||||||
label = li.getElement('.label'),
|
|
||||||
text = label.get('text').trim();
|
label.addEvent('blur', label.retrieve('$blur'));
|
||||||
|
|
||||||
if(label.get('contenteditable') == 'true'){
|
hasExtension = hasExtension || !!text.getFileExtension();
|
||||||
|
|
||||||
//validation
|
var range = document.createRange(),
|
||||||
text = File.sanitize(text);
|
node = label.firstChild;
|
||||||
|
range.setStart(node, 0);
|
||||||
|
range.setEnd(node, hasExtension ? text.length - text.getFileExtension().length -1 : text.length);
|
||||||
if (!text.getFileName()) {
|
sel = window.getSelection();
|
||||||
fd.error.alert('Filename must be valid', 'Your file must not contain special characters, and requires a file extension.');
|
sel.removeAllRanges();
|
||||||
return this;
|
sel.addRange(range);
|
||||||
}
|
|
||||||
|
return this;
|
||||||
label.removeEvent('blur', label.retrieve('$blur'));
|
},
|
||||||
label.eliminate('$text');
|
|
||||||
label.set('contenteditable', false).blur();
|
renameBranchCancel: function(element) {
|
||||||
window.getSelection().removeAllRanges();
|
var li = (element.get('tag') == 'li') ? element : element.getParent('li'),
|
||||||
|
label = li.getElement('.label'),
|
||||||
|
text = label.retrieve('$text').trim();
|
||||||
li.removeClass('editing');
|
|
||||||
//fire a renameCancel if the name didnt change
|
label.set('contenteditable', false);
|
||||||
if (text == label.get('title').trim()) {
|
if (text) {
|
||||||
this.fireEvent('renameCancel', li);
|
label.set('text', text);
|
||||||
return this;
|
}
|
||||||
}
|
label.eliminate('$text');
|
||||||
|
li.removeClass('editing');
|
||||||
label.set('title', text);
|
|
||||||
label.set('text', text);
|
},
|
||||||
|
|
||||||
|
renameBranchEnd: function(element) {
|
||||||
|
var li = (element.get('tag') == 'li') ? element : element.getParent('li'),
|
||||||
|
label = li.getElement('.label'),
|
||||||
|
text = label.get('text').trim();
|
||||||
|
|
||||||
|
if(label.get('contenteditable') == 'true'){
|
||||||
|
|
||||||
|
//validation
|
||||||
|
text = File.sanitize(text);
|
||||||
|
|
||||||
|
|
||||||
|
if (!text.getFileName()) {
|
||||||
|
fd.error.alert('Filename must be valid', 'Your file must not contain special characters, and requires a file extension.');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
label.removeEvent('blur', label.retrieve('$blur'));
|
||||||
|
label.eliminate('$text');
|
||||||
|
label.set('contenteditable', false).blur();
|
||||||
|
window.getSelection().removeAllRanges();
|
||||||
|
|
||||||
|
|
||||||
|
li.removeClass('editing');
|
||||||
|
//fire a renameCancel if the name didnt change
|
||||||
|
if (text == label.get('title').trim()) {
|
||||||
|
this.fireEvent('renameCancel', li);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
label.set('title', text);
|
||||||
|
label.set('text', text);
|
||||||
|
|
||||||
li.set('name', text);
|
li.set('name', text);
|
||||||
li.set('title', text);
|
li.set('title', text);
|
||||||
var path = this.getFullPath(li)
|
var path = this.getFullPath(li);
|
||||||
li.set('path', path);
|
li.set('path', path);
|
||||||
|
|
||||||
|
|
||||||
this.fireEvent('renameComplete', [li, path]);
|
this.fireEvent('renameComplete', [li, path]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteBranch: function(element) {
|
deleteBranch: function(element) {
|
||||||
element.dispose();
|
element.dispose();
|
||||||
this.collapse.prepare();
|
this.collapse.prepare();
|
||||||
this.fireEvent('deleteBranch', element);
|
this.fireEvent('deleteBranch', element);
|
||||||
},
|
},
|
||||||
|
|
||||||
addPath: function(obj, options){
|
addPath: function(obj, options){
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var suffix = options.suffix || '',
|
var suffix = options.suffix || '',
|
||||||
splitted = obj.getFullName().split('/'),
|
splitted = obj.get('fullName').split('/'),
|
||||||
elements = Array.clone(splitted),
|
elements = Array.clone(splitted),
|
||||||
end = splitted.length - 1,
|
end = splitted.length - 1,
|
||||||
selector = '',
|
selector = '',
|
||||||
el,
|
el,
|
||||||
target = options.target,
|
url = options.url,
|
||||||
id_prefix = this.options.id_prefix;
|
target = options.target,
|
||||||
|
id_prefix = this.options.id_prefix,
|
||||||
if (id_prefix) {
|
rel = (obj instanceof Module || obj instanceof Attachment) ?
|
||||||
id_prefix += '-';
|
'file':
|
||||||
}
|
'directory';
|
||||||
|
|
||||||
elements.each(function(name, i){
|
if (id_prefix) {
|
||||||
var path = splitted.slice(0, i + 1).join('/');
|
id_prefix += '-';
|
||||||
if (i == end){
|
}
|
||||||
var previous = elements[i - 1] ? elements[i - 1].getElement('ul') : (options.target.getElement('ul') || options.target);
|
|
||||||
el = elements[i] = previous.getChildren(selector += 'li[title='+ name + suffix +'] ')[0] || this.addBranch({
|
elements.each(function(name, i){
|
||||||
'title': obj.getShortName(),
|
var path = splitted.slice(0, i + 1).join('/');
|
||||||
'name': obj.getShortName(),
|
if (i == end){
|
||||||
'path': path,
|
var previous = elements[i - 1] ? elements[i - 1].getElement('ul') : (options.target.getElement('ul') || options.target);
|
||||||
'url': obj.options.url,
|
el = elements[i] = previous.getChildren(selector += 'li[title='+ name + suffix +'] ')[0] || this.addBranch({
|
||||||
'id': obj.getID(),
|
'title': obj.get('shortName'),
|
||||||
'rel': obj.options.type ? 'file' : 'directory',
|
'name': obj.get('shortName'),
|
||||||
'class': 'UI_File_Normal' + (options.nodrag ? ' nodrag' : '')
|
'path': path,
|
||||||
}, previous, options);
|
'url': url,
|
||||||
|
'id': options.id,
|
||||||
elements[i].store('file', obj);
|
'rel': rel,
|
||||||
} else {
|
'class': 'UI_File_Normal' + (options.nodrag ? ' nodrag' : '')
|
||||||
target = elements[i] = options.target.getElement(selector += '> ul > li[title='+ name +'] ') || this.addBranch({
|
}, previous, options);
|
||||||
'title': name,
|
|
||||||
'name': name,
|
elements[i].store('file', obj);
|
||||||
'rel': 'directory',
|
} else {
|
||||||
'id': id_prefix + path.replace(/\//g, '-'),
|
target = elements[i] = options.target.getElement(selector += '> ul > li[title='+ name +'] ') || this.addBranch({
|
||||||
'path': path
|
'title': name,
|
||||||
}, target, options);
|
'name': name,
|
||||||
}
|
'rel': 'directory',
|
||||||
|
'id': id_prefix + path.replace(/\//g, '-'),
|
||||||
}, this);
|
'path': path
|
||||||
|
}, target, options);
|
||||||
return el;
|
}
|
||||||
},
|
|
||||||
|
}, this);
|
||||||
getFullPath: function(branch) {
|
|
||||||
var name = branch.get('title'),
|
return el;
|
||||||
parentEl = branch.getParent('li');
|
},
|
||||||
|
|
||||||
if (!parentEl.hasClass('top_branch')) {
|
getFullPath: function(branch) {
|
||||||
name = this.getFullPath(parentEl) + '/' + name;
|
var name = branch.get('title'),
|
||||||
}
|
parentEl = branch.getParent('li');
|
||||||
return name;
|
|
||||||
},
|
if (!parentEl.hasClass('top_branch')) {
|
||||||
|
name = this.getFullPath(parentEl) + '/' + name;
|
||||||
setFullPath: function(branch, path) {
|
}
|
||||||
if (!path) path = this.getFullPath(branch);
|
return name;
|
||||||
branch.set('path', path);
|
},
|
||||||
return branch;
|
|
||||||
},
|
setFullPath: function(branch, path) {
|
||||||
|
if (!path) path = this.getFullPath(branch);
|
||||||
toElement: function() {
|
branch.set('path', path);
|
||||||
return this.element;
|
return branch;
|
||||||
}
|
},
|
||||||
|
|
||||||
|
toElement: function() {
|
||||||
|
return this.element;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
FileTree.Collapse = new Class({
|
FileTree.Collapse = new Class({
|
||||||
|
|
||||||
Extends: Collapse.LocalStorage,
|
Extends: Collapse.LocalStorage,
|
||||||
|
|
||||||
updateElement: function(element){
|
updateElement: function(element){
|
||||||
this.parent(element);
|
this.parent(element);
|
||||||
this.updatePath(element);
|
this.updatePath(element);
|
||||||
},
|
},
|
||||||
|
|
||||||
updatePath: function(element){
|
updatePath: function(element){
|
||||||
var parent = element.getParent('li'),
|
var parent = element.getParent('li'),
|
||||||
path = parent ? parent.get('path') : false;
|
path = parent ? parent.get('path') : false;
|
||||||
element.set('path', (path ? path + '/' : '') + (element.get('path') || '').split('/').getLast());
|
element.set('path', (path ? path + '/' : '') + (element.get('path') || '').split('/').getLast());
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
String.implement('getFileExtension', function() {
|
String.implement('getFileExtension', function() {
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче