moving events handlers from the Files (now Models) to the Controllers

This commit is contained in:
Sean McArthur 2011-10-26 09:02:10 -05:00
Родитель 1b69b49335
Коммит 5a0584a6ba
12 изменённых файлов: 279 добавлений и 186 удалений

Просмотреть файл

@ -30,9 +30,6 @@ var File = new Class({
}, },
destroy: function() { destroy: function() {
// refactor me
if (this.textarea) this.textarea.destroy();
//delete fd.editor_contents[this.get_editor_id()];
if (this.active) { if (this.active) {
// switch editor! // switch editor!
mod = null; mod = null;
@ -41,7 +38,6 @@ var File = new Class({
Object.each(this.pack.modules, function(mod) { Object.each(this.pack.modules, function(mod) {
if (!first) { if (!first) {
first = true; first = true;
mod.switchTo();
editor.sidebar.setSelectedFile(mod); editor.sidebar.setSelectedFile(mod);
} }
}); });
@ -57,37 +53,6 @@ var File = new Class({
this.fireEvent('destroy'); this.fireEvent('destroy');
}, },
onSelect: function() {
this.fireEvent('select');
},
switchTo: function() {
this.selectTab();
this.pack.editor.switchTo(this);
this.pack.editor.focus();
this.fireEvent('showEditor');
},
makeTab: function() {
var tab = this.tab = new (require('editor/views/Tabs').Tab)(editor.tabs.tabs, {
title: this.getShortName()
});
this.addEvent('change', function() {
$(tab).addClass('modified');
});
this.addEvent('reset', function() {
$(tab).removeClass('modified');
})
tab.file = this;
},
selectTab: function() {
if(!this.tab) {
this.makeTab();
}
editor.tabs.tabs.setSelected(this.tab);
},
setChanged: function(isChanged) { setChanged: function(isChanged) {
if (this.changed != isChanged) { if (this.changed != isChanged) {
this.fireEvent(isChanged ? 'change' : 'reset'); this.fireEvent(isChanged ? 'change' : 'reset');
@ -116,20 +81,6 @@ var Library = new Class({
this.addEvent('destroy', function(){ this.addEvent('destroy', function(){
delete pack.libraries[this.options.id_number]; delete pack.libraries[this.options.id_number];
}); });
if(this.options.append) {
this.append();
}
},
append: function() {
editor.sidebar.addPlugin(this);
},
onSelect: function() {
this.parent();
//open in a new tab, of course
window.open(this.options.view_url);
}, },
getID: function() { getID: function() {
@ -179,56 +130,14 @@ var Attachment = new Class({
// uid for editor items // uid for editor items
this.uid = this.getEditorID(); this.uid = this.getEditorID();
if (this.options.append) {
this.append();
}
this.addEvent('destroy', function(){ this.addEvent('destroy', function(){
delete pack.attachments[this.options.uid]; delete pack.attachments[this.options.uid];
}); });
// create editor // create editor
if (this.options.active && this.is_editable()) {
this.switchTo();
} else {
pack.editor.registerItem(this); pack.editor.registerItem(this);
}
},
onSelect: function() {
this.parent();
if (this.is_editable()) {
this.switchTo();
} else {
var template_start = '<div id="attachment_view"><h3>'
+this.options.filename+'</h3><div class="UI_Modal_Section">';
var template_end = '</div><div class="UI_Modal_Actions"><ul><li>'
+'<input type="reset" value="Close" class="closeModal"/>'
+'</li></ul></div></div>';
var template_middle = 'Download <a href="'
+this.options.get_url
+'">'
+this.options.filename
+'</a>';
if (this.is_image()) {
template_middle += '<p></p>';
var img = new Element('img', { src: this.options.get_url });
var spinner;
img.addEvent('load', function() {
if (spinner) spinner.destroy();
modal.position();
});
}
var modal = this.attachmentWindow = fd.displayModal(template_start+template_middle+template_end);
var target = $(this.attachmentWindow).getElement('.UI_Modal_Section p');
if (target) {
spinner = new Spinner(target);
spinner.show();
target.grab(img);
}
}
}, },
loadContent: function() { loadContent: function() {
// load data synchronously
var that = this, var that = this,
spinnerEl = $(this.tab); spinnerEl = $(this.tab);
new Request({ new Request({
@ -263,10 +172,6 @@ var Attachment = new Class({
return this.options.uid + this.options.code_editor_suffix; return this.options.uid + this.options.code_editor_suffix;
}, },
append: function() {
editor.sidebar.addData(this);
},
reassign: function(options) { reassign: function(options) {
// every revision, attachments that have changed get a new `uid`. // every revision, attachments that have changed get a new `uid`.
// since Attachments are currently kept track of via the `uid`, // since Attachments are currently kept track of via the `uid`,
@ -337,26 +242,10 @@ var Module = new Class({
delete pack.modules[this.options.filename]; delete pack.modules[this.options.filename];
}); });
if (this.options.append) {
this.append();
}
// an uid for the editor // an uid for the editor
this.uid = this.options.filename + this.options.suffix; this.uid = this.options.filename + this.options.suffix;
// create editor // create editor
if (this.options.main || this.options.active) {
this.switchTo();
} else {
pack.editor.registerItem(this); pack.editor.registerItem(this);
}
},
onSelect: function() {
this.parent();
this.switchTo();
},
append: function() {
editor.sidebar.addLib(this);
}, },
loadContent: function() { loadContent: function() {
@ -412,23 +301,6 @@ var Folder = new Class({
this.addEvent('destroy', function(){ this.addEvent('destroy', function(){
delete pack.folders[this.options.root_dir + '/' +this.options.name]; delete pack.folders[this.options.root_dir + '/' +this.options.name];
}); });
if (this.options.append) {
this.append();
}
},
append: function() {
if (this.options.root_dir == Folder.ROOT_DIR_LIB) {
editor.sidebar.addLib(this);
} else if (this.options.root_dir == Folder.ROOT_DIR_DATA) {
editor.sidebar.addData(this);
}
},
onSelect: function() {
this.parent();
$log('selected a Folder');
}, },
getFullName: function() { getFullName: function() {

Просмотреть файл

@ -163,18 +163,29 @@ module.exports = new Class({
// when typing in Save popover, you should be able to tab in a // when typing in Save popover, you should be able to tab in a
// logical order // logical order
this.save_el.addEvent('mouseenter', function(e) { //TODO: this is using MooTools mouseenter
if (this.save_el.node.addEvent) {
this.save_el.node.addEvent('mouseenter', function(e) {
controller.versionEl.focus(); controller.versionEl.focus();
}); });
} else {
this.save_el.addEvent('mouseenter', function(e) {
controller.versionEl.focus();
})
}
this.revision_message_el = dom.$('revision_message'); this.revision_message_el = dom.$('revision_message');
this.revision_message_el.addEvent('keypress', function(e) { this.revision_message_el.addEvent('keypress', function(e) {
if (e.key == 'tab') { //TODO: the dom Event system should make this possible
//if (e.key == 'tab') {
if (e.keyCode = 9) {
e.preventDefault(); e.preventDefault();
controller.save_el.focus(); controller.save_el.focus();
} }
}); });
this.attachEditor(); this.attachEditor();
this.attachSidebar();
this.attachTabs();
if (dom.$('jetpack_core_sdk_version')) { if (dom.$('jetpack_core_sdk_version')) {
@ -211,8 +222,9 @@ module.exports = new Class({
// iterate by modules and instantiate Module // iterate by modules and instantiate Module
this.options.modules.forEach(function(module) { this.options.modules.forEach(function(module) {
module.readonly = this.options.readonly; module.readonly = this.options.readonly;
module.append = true; var mod = this.modules[module.filename] = new Module(this,module);
this.modules[module.filename] = new Module(this,module); this.sidebar.addLib(mod);
if (module.main) this.editFile(mod);
}, this); }, this);
}, },
@ -220,8 +232,8 @@ module.exports = new Class({
// iterate through attachments // iterate through attachments
this.options.attachments.forEach(function(attachment) { this.options.attachments.forEach(function(attachment) {
attachment.readonly = this.options.readonly; attachment.readonly = this.options.readonly;
attachment.append = true; var att = this.attachments[attachment.uid] = new Attachment(this,attachment);
this.attachments[attachment.uid] = new Attachment(this,attachment); this.sidebar.addData(att);
}, this); }, this);
}, },
@ -229,15 +241,21 @@ module.exports = new Class({
// iterate through attachments // iterate through attachments
this.options.dependencies.forEach(function(plugin) { this.options.dependencies.forEach(function(plugin) {
plugin.readonly = this.options.readonly; plugin.readonly = this.options.readonly;
plugin.append = true; var lib = this.libraries[plugin.id_number] = new Library(this,plugin);
this.libraries[plugin.id_number] = new Library(this,plugin); this.sidebar.addPlugin(lib);
}, this); }, this);
}, },
instantiate_folders: function() { instantiate_folders: function() {
this.options.folders.forEach(function(folder) { this.options.folders.forEach(function(folder) {
folder.append = true; folder.append = true;
this.folders[folder.root_dir + '/' + folder.name] = new Folder(this, folder); var key = folder.root_dir + '/' + folder.name;
var f = this.folders[key] = new Folder(this, folder);
if (folder.root_dir == Folder.ROOT_DIR_LIB) {
this.sidebar.addLib(f);
} else if (folder.root_dir == Folder.ROOT_DIR_DATA) {
this.sidebar.addData(f);
}
}, this); }, this);
}, },
@ -443,6 +461,7 @@ module.exports = new Class({
//Package.Edit //Package.Edit
attachEditor: function() { attachEditor: function() {
var controller = this; var controller = this;
if(!this.editor) return;
this.editor.addEvent('change', function() { this.editor.addEvent('change', function() {
controller.onChanged(); controller.onChanged();
@ -453,6 +472,81 @@ module.exports = new Class({
this.addEvent('reset', this.onReset); this.addEvent('reset', this.onReset);
}, },
attachSidebar: function() {
if (!this.sidebar) return;
var controller = this;
this.sidebar.addEvent('select', function(file) {
controller.onSidebarSelect(file);
});
},
attachTabs: function() {
if (!this.tabs) return;
var controller = this;
this.tabs.addEvent('select', function(tab) {
controller.onTabSelect(tab);
})
},
onSidebarSelect: function(file) {
// if file is Module or Editable Attachment
if ((file instanceof Module) ||
(file instanceof Attachment && file.isEditable())) {
// then open tab and editor
this.editFile(file);
}
// else if uneditable Attachment
else if (file instanceof Attachment) {
// then show in fd.modal
this.showAttachmentModal(file);
}
// else if Library
else if (file instanceof Library) {
// then open link in new window
window.open(file.options.view_url);
}
},
onTabSelect: function(tab) {
this.editFile(tab.file);
},
editFile: function(file) {
this.tabs.selectTab(file);
this.editor.switchTo(file).focus();
},
showAttachmentModal: function(file) {
var template_start = '<div id="attachment_view"><h3>'
+file.options.filename+'</h3><div class="UI_Modal_Section">';
var template_end = '</div><div class="UI_Modal_Actions"><ul><li>'
+'<input type="reset" value="Close" class="closeModal"/>'
+'</li></ul></div></div>';
var template_middle = 'Download <a href="'
+file.options.get_url
+'">'
+file.options.filename
+'</a>';
if (file.is_image()) {
template_middle += '<p></p>';
var img = new Element('img', { src: file.options.get_url });
var spinner;
img.addEvent('load', function() {
if (spinner) spinner.destroy();
modal.position();
});
}
var modal = fd.displayModal(template_start+template_middle+template_end);
var target = $(modal).getElement('.UI_Modal_Section p');
if (target) {
spinner = new Spinner(target);
spinner.show();
target.grab(img);
}
},
onChanged: function() { onChanged: function() {
$log('FD: INFO: document changed - onbeforeunload warning is on and save button is lit.'); $log('FD: INFO: document changed - onbeforeunload warning is on and save button is lit.');
dom.$$('li.Icon_save').addClass('Icon_save_changes'); dom.$$('li.Icon_save').addClass('Icon_save_changes');
@ -1344,11 +1438,9 @@ module.exports = new Class({
}, },
alertUnsavedData: function(e) { alertUnsavedData: function(e) {
if (this.edited && fd.saving) { if (this.edited && !fd.saving) {
e.preventDefault(); e.preventDefault();
e.returnValue = "You've got unsaved changes.";
} }
} }
}); });

Просмотреть файл

@ -10,19 +10,24 @@ var Class = require('shipyard/class/Class'),
module.exports = new Class({ module.exports = new Class({
Implements: Events,
$tabs: [],
initialize: function() { initialize: function() {
var controller = this;
this.tabs = new tabs.TabBar('editor-tabs', { this.tabs = new tabs.TabBar('editor-tabs', {
arrows: false, arrows: false,
onTabDown: function(tab) { onTabDown: function(tab) {
if (!tab.hasClass('selected')) { if (!tab.hasClass('selected')) {
tab.retrieve('tab:instance').file.onSelect(); controller.fireEvent('select', tab.retrieve('tab:instance'));
} }
}, },
onCloseDown: function(tabClose) { onCloseDown: function(tabClose) {
var tabEl = tabClose.getParent('.tab'); var tabEl = tabClose.getParent('.tab');
var nextTab = tabEl.hasClass('selected') ? var nextTab = tabEl.hasClass('selected') ?
tabEl.getPrevious('.tab.') || tabEl.getNext('.tab') : tabEl.getPrevious('.tab') || tabEl.getNext('.tab') :
$(tabs).getElement('.tab.selected'); $(controller.tabs).getElement('.tab.selected');
if(nextTab) { if(nextTab) {
var tab = tabEl.retrieve('tab:instance'), var tab = tabEl.retrieve('tab:instance'),
that = this, that = this,
@ -58,7 +63,7 @@ module.exports = new Class({
file.setChanged(false); file.setChanged(false);
fd.item.edited--; fd.item.edited--;
if(!fd.item.edited) { if(!fd.item.edited) {
fd.fireEvent('reset'); fd.item.fireEvent('reset');
} }
}, 1); }, 1);
} }
@ -73,6 +78,60 @@ module.exports = new Class({
} }
}); });
},
addTab: function(file) {
var controller = this;
var tab = new tabs.Tab(this.tabs, {
title: file.getShortName()
});
function change() {
$(tab).addClass('modified');
}
function reset() {
$(tab).removeClass('modified');
}
file.addEvent('change', change);
file.addEvent('reset', reset);
tab.addEvent('destroy', function() {
file.removeEvent('change', change);
file.removeEvent('reset', reset);
controller.removeTab(tab);
});
tab.file = file;
this.$tabs.push(tab);
return tab;
},
removeTab: function(tab) {
//For now, simply pops the tab off the internal $tabs array
//TODO: this should probably be where all the tab destruction
//happens, instead of that massive indent-monster in the
//initialize method
var index = this.$tabs.indexOf(tab);
if (index) {
this.$tabs.splice(index, 1);
}
},
selectTab: function(file) {
var tab = this.getTab(file) || this.addTab(file);
this.tabs.setSelected(tab);
},
getTab: function(file) {
for (var i = 0, len = this.$tabs.length; i < len; i++) {
if (this.$tabs[i].file == file) {
return this.$tabs[i];
}
}
} }
}); });

Просмотреть файл

@ -1,16 +1,13 @@
var Class = require('shipyard/class/Class'), var Class = require('shipyard/class/Class'),
Model = require('shipyard/model/Model'),
fields = require('shipyard/model/fields'), fields = require('shipyard/model/fields'),
Syncable = require('shipyard/sync/Syncable'), ServerSync = require('shipyard/sync/Server'),
ServerSync = require('shipyard/sync/Server');
File = require('./File');
var EDITABLE_EXTS = ['js', 'css', 'html', 'txt', 'md', 'markdown', 'json'];
module.exports = new Class({ module.exports = new Class({
Extends: Model, Extends: File,
Implements: Syncable,
Sync: { Sync: {
'default': { 'default': {
@ -20,19 +17,8 @@ module.exports = new Class({
}, },
fields: { fields: {
id: fields.NumberField(),
filename: fields.TextField({ required: true }),
ext: fields.TextField(),
url: fields.TextField(), url: fields.TextField(),
data: fields.TextField()} data: fields.TextField()
},
toString: function() {
return this.get('filename') + '.' + this.get('ext');
},
isEditable: function() {
return EDITABLE_EXTS.indexOf(this.get('ext')) !== -1;
} }
}); });

Просмотреть файл

@ -0,0 +1,41 @@
// Abstract model
var Class = require('shipyard/class/Class'),
Model = require('shipyard/model/Model'),
fields = require('shipyard/model/fields'),
Syncable = require('shipyard/sync/Syncable');
var File = module.exports = new Class({
Extends: Model,
Implements: Syncable,
fields: {
id: fields.NumberField(),
filename: fields.TextField({ required: true }),
ext: fields.TextField({ 'default': 'js' }),
content: fields.TextField()
},
shortName: function() {
return this.get('fullName').split('/').pop();
},
fullName: function() {
var name = this.get('filename'),
ext = this.get('ext');
if (ext) {
return name + '.' + ext;
} else {
return name;
}
},
isEditable: function() {
return this.constructor.EDITABLE_EXTS.indexOf(this.get('ext')) !== -1;
}
});
File.EDITABLE_EXTS = ['js', 'html', 'css', 'txt', 'json', 'md'];

Просмотреть файл

@ -1,14 +1,11 @@
var Class = require('shipyard/class/Class'), var Class = require('shipyard/class/Class'),
Model = require('shipyard/model/Model'), File = require('./File'),
fields = require('shipyard/model/fields'), fields = require('shipyard/model/fields'),
Syncable = require('shipyard/sync/Syncable'),
ServerSync = require('shipyard/sync/Server'); ServerSync = require('shipyard/sync/Server');
module.exports = new Class({ module.exports = new Class({
Extends: Model, Extends: File,
Implements: Syncable,
Sync: { Sync: {
'default': { 'default': {
@ -18,9 +15,6 @@ module.exports = new Class({
}, },
fields: { fields: {
id: fields.NumberField(),
filename: fields.TextField(),
code: fields.TextField()
} }
}); });

Просмотреть файл

@ -218,6 +218,7 @@ module.exports = {
expect(versionFocus.getCallCount()).toBe(1); expect(versionFocus.getCallCount()).toBe(1);
var tab = new E; var tab = new E;
tab.keyCode = 9;
tab.key = 'tab'; tab.key = 'tab';
pc.revision_message_el.fireEvent('keypress', tab); pc.revision_message_el.fireEvent('keypress', tab);
expect(saveFocus.getCallCount()).toBe(1); expect(saveFocus.getCallCount()).toBe(1);

Просмотреть файл

@ -0,0 +1,32 @@
var Attachment = require('../../models/Attachment');
module.exports = {
'Attachment': function(it, setup) {
it('should get fullName from filename + ext', function(expect) {
var att = new Attachment({ filename: 'example.mode.html' });
expect(att.get('fullName')).toBe('example.mode.html.js');
att.set('filename', 'example/mode.html');
att.set('ext', 'txt');
expect(att.get('fullName')).toBe('example/mode.html.txt');
});
it('should be able to get shortName', function(expect) {
var att = new Attachment({ filename: 'really/long/path/file' });
expect(att.get('shortName')).toBe('file.js');
});
it('should be editable if a text type', function(expect) {
var att = new Attachment;
expect(att.isEditable()).toBe(true);
att.set('ext', 'css');
expect(att.isEditable()).toBe(true);
});
it('should not be editable if img', function(expect) {
var att = new Attachment({ ext: 'png' });
expect(att.isEditable()).toBe(false);
});
}
}

Просмотреть файл

@ -0,0 +1,19 @@
var Module = require('../../models/Module');
module.exports = {
'Module': function(it, setup) {
it('should be able to get fullName (filename + ext)', function(expect) {
var m = new Module({ filename: 'events/key.press' });
expect(m.get('fullName')).toBe('events/key.press.js')
});
it('should be able to get shortName', function(expect) {
var m = new Module({ filename: 'main'});
expect(m.get('shortName')).toBe('main.js');
m.set('filename', 'events/key.down');
expect(m.get('shortName')).toBe('key.down.js');
})
}
}

Просмотреть файл

@ -99,10 +99,12 @@ var FDEditor = module.exports = new Class({
this.deactivateCurrent(); this.deactivateCurrent();
} }
this.activateItem(item); this.activateItem(item);
return this;
}, },
dumpCurrent: function() { dumpCurrent: function() {
this.current.content = this.getContent(); this.current.content = this.getContent();
return this;
}, },
setReadOnly: function() { setReadOnly: function() {

Просмотреть файл

@ -252,12 +252,6 @@ var Sidebar = module.exports = new Class({
element.erase('file'); element.erase('file');
}); });
file.addEvent('select', function() {
if (file.is_editable()) {
that.setSelectedFile(file);
}
});
// file.onChange should add an asterisk to the tree branch // file.onChange should add an asterisk to the tree branch
// file.onReset should remove the asterisk // file.onReset should remove the asterisk
file.addEvent('change', function() { file.addEvent('change', function() {
@ -356,9 +350,8 @@ var Sidebar = module.exports = new Class({
selectFile: function(li) { selectFile: function(li) {
var file = li.retrieve('file'); var file = li.retrieve('file');
if(file) { this.fireEvent('select', file);
file.onSelect(); this.setSelectedFile(li);
}
}, },
silentlyRemoveFolders: function(element) { silentlyRemoveFolders: function(element) {

Просмотреть файл

@ -53,6 +53,8 @@ var Tab = new Class({
destroy: function() { destroy: function() {
this.fireEvent('destroy'); this.fireEvent('destroy');
this.removeEvents();
this.element = this.element.destroy(); this.element = this.element.destroy();
this.close = this.close.destroy(); this.close = this.close.destroy();
this.file.tab = null; this.file.tab = null;