Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENYO-1020: implement "Save As" under the Text Editor #243

Merged
merged 23 commits into from
Mar 29, 2013
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2e6594a
ENYO-1020: editor: turn `Save` button into `File` menu…
Mar 20, 2013
70c27b5
ENYO-1020: Fix typo in `EditorSettings` breaking the `chrome` theme
Mar 20, 2013
339007f
ENYO-1020: `DirectorySelectorPopup` is now `FileChooser`
Mar 20, 2013
38053bb
Merge remote-tracking branch 'enyojs/master' into ENYO-1020
Mar 25, 2013
537b486
ENYO-1020: Move top-level Ares MVC components under ares/source/
Mar 25, 2013
5d6c9c5
ENYO-2104: refresh Ares usage instructions
Mar 25, 2013
10eecb9
ENYO-1020: Move top-level Ares MVC components under ares/source/ (2/2)
Mar 25, 2013
26ba6fa
ENYO-1020: add /favicon.ico (avoid 404 in the logs...)
Mar 25, 2013
d0b53bc
ENYO-2104: remove misleading runares.bat
Mar 25, 2013
473c47e
ENYO-1020: add `ares.basename()` and `ares.dirname()` utilities
Mar 27, 2013
060d91a
ENYO-1996: Added getParentOfSelected method on HermesFileTree
Mar 28, 2013
469e3b4
ENYO-1020: share waitPopup between Ares & Phobos
Mar 28, 2013
24cd519
ENYO-1020: refactor FileChooser to be a filePicker or a folderPicker
Mar 29, 2013
a9dda05
ENYO-1020: implement Phobos#saveAs
Mar 29, 2013
dc13cdc
ENYO-1020: remove dead code (Documents.js)
Mar 29, 2013
80ac06c
ENYO-1020: update FS protocol description, following @opopova comment
Mar 29, 2013
3156e11
Merge branch 'master' of github.com:enyojs/ares-project into ENYO-1020
Mar 29, 2013
b85335c
ENYO-1020: decrease FileChooser tracing level.
Mar 29, 2013
dc8be21
ENYO-2089: refresh the FileTree after `Save As…`
Mar 29, 2013
7c0f3dd
ENYO-2089: review comment: add Ares icon attribution
Mar 29, 2013
0b63dd1
ENYO-1020: fix review comment (typo)
Mar 29, 2013
742da01
ENYO-1020: fix bug introduced while addressing review comment
Mar 29, 2013
a846119
ENYO-1020: address review comment (clarify)
Mar 29, 2013
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 29 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

Ares 2 is a browser-based code editor and UI designer for developing Enyo 2 applications. Although Ares is still a work in progress, we have reached the point where we are opening the repo and will do further development in the open, so we encourage you to follow our progress and give us feedback as we push Ares forward.

You can give us feedback either via the [Ares category of the EnyoJS Forums](http://forums.enyojs.com/categories/ares) or via the [EnyoJS JIRA](https://enyojs.atlassian.net/) (using the `ares` component).

### Basic architecture

The Ares project architecture is divided into several main pieces:
Expand Down Expand Up @@ -36,14 +38,14 @@ Here are the main features you can start looking at today:

The following features are in the works, and you should see them added as we move forward:

* Code completion and context-sensitive documentation
* More code completion and context-sensitive documentation
* Additional Hermes components to extend the local and cloud file storage options: We plan to add Hermes components for FTP, Box.net and more
* Improvements to the Designer component for greater ease of use
* ... and more!

**Note:** An up-to-date view of the ongoing activities is available from The [ARES JIRA](https://enyojs.atlassian.net/browse/ENYO/component/10302), itself available from the [EnyoJS JIRA](https://enyojs.atlassian.net/browse/ENYO).

### Install
### Install Ares

1. Install Node.js & NPM 0.8.x (>= 0.8.19). Preferably from the [Official Download Page](http://nodejs.org/#download).
1. Run:
Expand All @@ -52,13 +54,18 @@ The following features are in the works, and you should see them added as we mov

The `-d` options gives some minimal troubleshooting information, which is pretty useful as `ares-ide` is a heavy package (more than 12 MB).

### Develop
1. Once installed, run it using `node_modules/.bin/ares-ide` (or `node_modules\.bin\ares-ide.cmd`) on Windows.
1. Please report the issues you find in our JIRA at [https://enyojs.atlassian.net/](https://enyojs.atlassian.net/) against the component named `ares`.

In case you do not yet have a development environment:
### Develop Ares

1. Install Node.js & NPM 0.8.x (>= 0.8.19). Preferably from the [Official Download Page](http://nodejs.org/#download).
1. Install git (or a graphical git client). See the [Github.com help](https://help.github.com/articles/set-up-git) for hints
1. Pick a GitHub account & clone the ares-project repository from GitHub. Using git, clone the repository using either the HTTPS or SSH urls (depending on how you have setup Git):
1. Pick a GitHub account

**Fresh workspace**, in case you do not yet have a development environment:

1. Clone the ares-project repository from GitHub. Using git, clone the repository using either the HTTPS or SSH urls (depending on how you have setup Git):

$ git clone --recursive git@github.com:enyojs/ares-project.git

Expand All @@ -68,25 +75,34 @@ In case you do not yet have a development environment:

$ npm -d install

If you already have a working environment (with a remote named `origin`), run the following sequence.
1. Run Ares using `node ide.js` from the GitHub root folder

**Update workspace** if you already have a working environment (with a remote named `origin`), run the following sequence.

$ git fetch origin
$ git submodule foreach git fetch origin
$ git merge origin/master
$ git submodule update --init
$ git submodule update --init --recursive
$ npm -d install

**Note:** Until recently, `ares-project/node_modules` contained 3rd-party modules directly archived into `ares-project` own Git repository. So existing repository owners _may_ need to run `rm -rf ares-project/node_modules` to properly update their trees.
**Note:**

1. Until recently, `ares-project/node_modules` contained 3rd-party modules directly archived into `ares-project` own Git repository. So existing repository owners _may_ need to run `rm -rf ares-project/node_modules` to properly update their trees.
2. Do **NOT** use Node.js 0.10.0: Ares does not work yet using this brand new version of Node. [We are aware of the issue](https://enyojs.atlassian.net/browse/ENYO-2063).

### Use Ares to Develop Applications

Start the IDE server: (e.g. using the Command Prompt, navigate to the ares directory and type 'node ide.js')…

### Run
C:\Users\johndoe\node_modules\.bin> ares-ide.cmd

Start the IDE server: (e.g. using the Command Prompt, navigate to the ares directory and type 'node ide.js')
… or (Mac & Linux):

C:\Users\johndoe\GIT\ares-project> node ide.js
$ node_modules/.bin/ares-ide

Get more information about the options using `-h` or `--help`:

$ node ide.js --help
$ ares-ide --help

Ares IDE, a front-end designer/editor web applications.
Usage: "node ./ide.js" [OPTIONS]
Expand Down Expand Up @@ -135,7 +151,7 @@ In order to produce Ares on a build server:
$ npm install ../ares-project/ares-ide-0.0.2.tgz
$ node_modules/.bin/ares-ide

### Publish
### Release & Publish

_This section is for Ares commiters only_

Expand Down
25 changes: 25 additions & 0 deletions ares/Ares.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,24 @@ body {
}

/**/

.ares-filechooser {
height: 400px;
width: 600px;
}

.ares-filechooser-header {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why 2 classes with the same properties ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although they have the same properties now (and their visual look is equally ugly), they are not use at the same place & I expect them to evolve differently as @opopova will work on them.

padding: 0 0.5em;
vertical-align: middle;
}

.ares-filechooser-footer {
padding: 0 0.5em;
vertical-align: middle;
}

/**/

.ares-groupbox-item-key {
padding: 0.5em;
}
Expand Down Expand Up @@ -260,6 +278,13 @@ body {
.onyx-popup {
font-size: 13px;
}
.onyx-input-decorator > input {
font-size: 13px;
}
.onyx-input-decorator {
padding:2px 8px;
margin:0px;
}
.onyx-button {
font-size: 13px;
padding:2px 8px;
Expand Down
Binary file removed ares/ares-128.png
Binary file not shown.
Binary file removed ares/ares-16.png
Binary file not shown.
Binary file added ares/assets/images/ares_48x48.ico
Binary file not shown.
Binary file added ares/assets/images/ares_48x48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion ares/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ enyo.depends(
"$lib/foss",
"source/",
"Ares.css",
"../model/source",
"$lib/extra/analyzer2",
"../utilities/source",
"../services/source",
Expand Down
182 changes: 131 additions & 51 deletions ares/source/Ares.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ enyo.kind({
components: [
{kind: "Panels", arrangerKind: "CarouselArranger", draggable: false, classes:"enyo-fit ares-panels", components: [
{components: [
{kind: "Phobos", onSaveDocument: "saveDocument", onCloseDocument: "closeDocument", onDesignDocument: "designDocument", onUpdate: "phobosUpdate"}
{kind: "Phobos", onSaveDocument: "saveDocument", onSaveAsDocument: "saveAsDocument", onCloseDocument: "closeDocument", onDesignDocument: "designDocument", onUpdate: "phobosUpdate"}
]},
{components: [
{kind: "Deimos", onCloseDesigner: "closeDesigner", onDesignerUpdate: "designerUpdate", onUndo: "designerUndo", onRedo: "designerRedo"}
]}
]},
{kind: "Slideable", layoutKind: "FittableRowsLayout", classes: "onyx ares-files-slider", axis: "v", value: 0, min: -500, max: 0, unit: "px", onAnimateFinish: "finishedSliding", components: [
{kind: "ProjectView", fit: true, classes: "onyx", onFileDblClick: "doubleclickFile", onProjectSelected: "projectSelected"},
{name: "projectView", kind: "ProjectView", fit: true, classes: "onyx", onFileDblClick: "openDocument", onProjectSelected: "projectSelected"},
{name: "bottomBar", kind: "DocumentToolbar",
onToggleOpen: "toggleFiles",
onSwitchFile: "switchFile",
Expand All @@ -24,15 +24,15 @@ enyo.kind({
}
]},
{name: "waitPopup", kind: "onyx.Popup", centered: true, floating: true, autoDismiss: false, modal: true, style: "text-align: center; padding: 20px;", components: [
{kind: "Image", src: "$phobos/images/save-spinner.gif", style: "width: 54px; height: 55px;"},
{kind: "Image", src: "$phobos/assets/images/save-spinner.gif", style: "width: 54px; height: 55px;"},
{name: "waitPopupMessage", content: "Ongoing...", style: "padding-top: 10px;"}
]},
{kind: "ServiceRegistry"}
],
handlers: {
onReloadServices: "handleReloadServices",
onUpdateAuth: "handleUpdateAuth",
onShowWaitPopup: "handleShowWaitPopup",
onShowWaitPopup: "showWaitPopup",
onHideWaitPopup: "hideWaitPopup"
},
phobosViewIndex: 0,
Expand Down Expand Up @@ -71,65 +71,148 @@ enyo.kind({
if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
this.$.serviceRegistry.setConfig(inEvent.serviceId, {auth: inEvent.auth}, inEvent.next);
},
doubleclickFile: function(inSender, inEvent) {
var f = inEvent.file;
var id = Ares.Workspace.files.computeId(f);
var d = Ares.Workspace.files.get(id);
if (d) {
this.switchToDocument(d);
} else {
this.$.bottomBar.createFileTab(f.name, id);
this.$.slideable.setDraggable(true);
this.openDocument(inSender, inEvent);
}
},
projectSelected: function() {
setTimeout(enyo.bind(this, function() { this.$.deimos.projectSelected(this.$.projectView.currentProject); }), 500); // <-- TODO - using timeout here because project url is set asynchronously
return true;
},
openDocument: function(inSender, inEvent) {
var f = inEvent.file;
var projectData = inEvent.projectData;

var service = projectData.getService();
this.$.phobos.beginOpenDoc();
service.getFile(f.id)
.response(this, function(inEvent, inData) {
if (inData.content) {
inData=inData.content;
this._openDocument(inEvent.projectData, inEvent.file, function(inErr) {});
},
/** @private */
_openDocument: function(projectData, file, next) {
var self = this;
var fileDataId = Ares.Workspace.files.computeId(file);
var fileData = Ares.Workspace.files.get(fileDataId);
if (fileData) {
this.switchToDocument(fileData);
} else {
this.showWaitPopup(this, {msg: $L("Opening...")});
this.$.bottomBar.createFileTab(file.name, fileDataId);
this.$.slideable.setDraggable(true);
this._fetchDocument(projectData, file, function(inErr, inContent) {
self.hideWaitPopup();
if (inErr) {
self.warn("Open failed", inErr);
} else {
// no data? Empty file
inData="";
}
var id = Ares.Workspace.files.computeId(f);
if (Ares.Workspace.files.get(id)) {
alert("Duplicate File ID in cache!");
fileData = Ares.Workspace.files.newEntry(file, inContent, projectData);
self.switchToDocument(fileData);
}
var doc = Ares.Workspace.files.newEntry(f, inData, projectData);
this.switchToDocument(doc);
})
.error(this, function(inEvent, inData) {
enyo.log("Open failed", inData);
this.$.phobos.hideWaitPopup();
});
}
},
saveDocument: function(inSender, inEvent) {
var service = inEvent.file.service;
service.putFile(inEvent.file.id, inEvent.content)
/** @private */
_fetchDocument: function(projectData, file, next) {
if (this.debug) this.log("projectData:", projectData, ", file:", file);
var service = projectData.getService();
service.getFile(file.id)
.response(this, function(inEvent, inData) {
inSender.saveComplete();
this.$.deimos.saveComplete();
next(null, inData && inData.content || "");
})
.error(this, function(inEvent, inData) {
inSender.saveFailed(inData);
.error(this, function(inEvent, inErr) {
next(inErr);
});
},
saveDocument: function(inSender, inEvent) {
if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
var self = this;
this._saveDocument(inEvent.content, {service: inEvent.file.service, fileId: inEvent.file.id}, function(err) {
if (err) {
self.$.phobos.saveFailed(err);
} else {
self.$.phobos.saveComplete();
self.$.deimos.saveComplete();
}
});
},
_saveDocument: function(content, where, next) {
var req;
if (where.fileId) {
req = where.service.putFile(where.fileId, content);
} else {
req = where.service.createFile(where.folderId, where.name, content);
}
req.response(this, function(inEvent, inData) {
next(null, inData);
}).error(this, function(inEvent, inErr) {
next(inErr);
});

},
saveAsDocument: function(inSender, inEvent) {
if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
var self = this,
file = inEvent.file,
name = inEvent.name,
content = inEvent.content;

if (!file) {
_footer(new Error("missing file/folder description"));
return;
}

async.waterfall([
this._closeDocument.bind(this, inEvent.docId),
function(next) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the purpose of this anonymous function is not easy to understand. You should either add a comment or put this function in a local variable with a descriptive name. The latter is preferred as the waterfall sequence would be easier to read

var where, err;
if (file.isDir && name) {
// create given file in given dir
where = {
service: file.service,
folderId: file.id,
name: name
};
} else if (!file.isDir && !name) {
// overwrite the given file
where = {
service: file.service,
fileId: file.id
};
} else if (!file.isDir && name) {
// create a new file in the same folder as the
// given file
where = {
service: file.service,
folderId: file.parent.id,
name: name
};
} else {
err = new Error("wrong file/folder description");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe mention that's an internal error.

}
next(err, where);
},
this._saveDocument.bind(this, inEvent.content),
_savedToOpen.bind(this),
this._openDocument.bind(this, inEvent.projectData)
], _footer);

function _savedToOpen(inData, next) {
this.$.projectView.refreshFile(file);
// FIXME: only HermesFileTree report built-in file#service
var hermesFile = inData[0];
hermesFile.service = file.service;
hermesFile.name = ares.basename(hermesFile.path);
next(null, hermesFile);
}

function _footer(err, result) {
if (self.debug) enyo.log("err:", err, "result:", result);
if (typeof inEvent.next === 'function') {
inEvent.next(err, result);
}
}
},
closeDocument: function(inSender, inEvent) {
if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
this._closeDocument(inEvent.id, function() {});
},
/** @private */
_closeDocument: function(docId, next) {
// remove file from cache
Ares.Workspace.files.removeEntry(inEvent.id);
this.$.bottomBar.removeTab(inEvent.id);
Ares.Workspace.files.removeEntry(docId);
this.$.bottomBar.removeTab(docId);
this.$.slideable.setDraggable(Ares.Workspace.files.length > 0);
this.showFiles();
next();
},
designDocument: function(inSender, inEvent) {
this.syncEditedFiles();
Expand Down Expand Up @@ -282,11 +365,8 @@ enyo.kind({
syncJSFile: function(inCode) {
this.$.deimos.syncJSFile(inCode);
},
handleShowWaitPopup: function(inSender, inEvent) {
this.showWaitPopup(inEvent.msg);
},
showWaitPopup: function(inMessage) {
this.$.waitPopupMessage.setContent(inMessage);
showWaitPopup: function(inSender, inEvent) {
this.$.waitPopupMessage.setContent(inEvent.msg);
this.$.waitPopup.show();
},
hideWaitPopup: function() {
Expand Down
File renamed without changes.
File renamed without changes.
4 changes: 3 additions & 1 deletion ares/source/package.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
enyo.depends(
"Ares.js",
"DocumentToolbar.js"
"DocumentToolbar.js",
"FileData.js",
"WorkspaceData.js"
);
Loading