Skip to content

Loading…

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

Merged
merged 23 commits into from

2 participants

@asnowfix
Enyo JavaScript framework member

Tested on OSX/ChromeCanary, OSX/Opera (so far), OSX/Firefox (SaveAs works , not Save, due to https://enyojs.atlassian.net/browse/ENYO-1269)

  • ENYO-1020: update FS protocol description, following @opopova comment
  • ENYO-1020: remove dead code (Documents.js)
  • ENYO-1020: implement Phobos#saveAs
  • ENYO-1020: refactor FileChooser to be a filePicker or a folderPicker
  • ENYO-1020: share waitPopup between Ares & Phobos
  • ENYO-1996: Added getParentOfSelected method on HermesFileTree
  • ENYO-1020: add ares.basename() and ares.dirname() utilities
  • ENYO-2104: remove misleading runares.bat
  • ENYO-1020: add /favicon.ico (avoid 404 in the logs...)
  • ENYO-1020: Move top-level Ares MVC components under ares/source/ (2/2)
  • ENYO-2104: refresh Ares usage instructions
  • ENYO-1020: Move top-level Ares MVC components under ares/source/
  • Merge remote-tracking branch 'enyojs/master' into ENYO-1020
  • ENYO-1020: DirectorySelectorPopup is now FileChooser
  • ENYO-1020: Fix typo in EditorSettings breaking the chrome theme
  • ENYO-1020: editor: turn Save button into File menu…

Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI francois-xavier.kowalski@hp.com

asnowfix and others added some commits
@asnowfix asnowfix ENYO-1020: editor: turn `Save` button into `File` menu…
- `File` menu has `Save`, `Save as` and `Close` menu items.

Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
2e6594a
@asnowfix asnowfix ENYO-1020: Fix typo in `EditorSettings` breaking the `chrome` theme
Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
70c27b5
@asnowfix asnowfix ENYO-1020: `DirectorySelectorPopup` is now `FileChooser`
- `DirectorySelectorPopup` is now `Ares.FileChooser` defined by
  `utilities/source/FileChooser`
- Move manual `style:`  into `Ares.css` as `.ares-filechooser*`

Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
339007f
@asnowfix asnowfix Merge remote-tracking branch 'enyojs/master' into ENYO-1020 38053bb
@asnowfix asnowfix ENYO-1020: Move top-level Ares MVC components under ares/source/
- the `model/` tree was not attached to one of the functional Ares
  components (Ares, Harmonia, Phobos, Deimos)

Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
537b486
@asnowfix asnowfix ENYO-2104: refresh Ares usage instructions
- git clone is no longer the primary way of delivering Ares

Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
5d6c9c5
@asnowfix asnowfix ENYO-1020: Move top-level Ares MVC components under ares/source/ (2/2)
- fix broken package.js

Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
10eecb9
@asnowfix asnowfix ENYO-1020: add /favicon.ico (avoid 404 in the logs...)
- remove former ares.png files fetched from the Net with random license
- add icon from Ares1 (https://ares.palm.com) as favicon.ico

Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
26ba6fa
@asnowfix asnowfix ENYO-2104: remove misleading runares.bat
- prefer to use NPM-generated wrappers

Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
d0b53bc
@asnowfix asnowfix ENYO-1020: add `ares.basename()` and `ares.dirname()` utilities
Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
473c47e
@dod38fr dod38fr ENYO-1996: Added getParentOfSelected method on HermesFileTree 060d91a
@dod38fr dod38fr ENYO-1020: share waitPopup between Ares & Phobos
- Former implementation fires up one, the other one or both without
  a well-defined (or understandable) logic.
- New implementation uses a single Ares#waitPopup that is usable via
  events by any module of Ares.

Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
469e3b4
@asnowfix asnowfix ENYO-1020: refactor FileChooser to be a filePicker or a folderPicker
- Still used by ProjectWizard (folderPicker)
- Ready to be used by Phobos#saveAs (filePicker)

Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
24cd519
@asnowfix asnowfix ENYO-1020: implement Phobos#saveAs
- UI interaction is handled by Phobos (text editor), which raises events
- Events are trapped at the Ares level, which implements async file-
  system operations & report their success back to Phobos
- FIXME: Phobos#saveAs() uses a common-JS type of completion callback
  (which is good) while Phobos#save() makes Ares directly call into
  Phobos's API (which is ugly, because Ares needs to know about an async
  operation completion public API which does not need to exist).
- FIXME: saveAs popup does not show the folder where the current file
  is.  This is Ok in case of multiple saveAs (operation resumes in the
  same folder as before), but not for the first popup.

Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
a9dda05
@asnowfix asnowfix ENYO-1020: remove dead code (Documents.js)
Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
dc13cdc
@asnowfix asnowfix ENYO-1020: update FS protocol description, following @opopova comment
Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
80ac06c
@asnowfix asnowfix Merge branch 'master' of github.com:enyojs/ares-project into ENYO-1020 3156e11
@dod38fr dod38fr was assigned
@asnowfix asnowfix ENYO-1020: decrease FileChooser tracing level.
Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
b85335c
@dod38fr
Enyo JavaScript framework member

File 'saved as...' is not shown in HermesFileTree of the project. HermesFileTree should be refreshed once the file is saved

@dod38fr
Enyo JavaScript framework member

tested on:

  • Debian with Chromium and firefox 10.
  • Windows7 with IE9
@dod38fr dod38fr commented on the diff
ares/Ares.css
@@ -28,6 +28,24 @@ body {
}
/**/
+
+.ares-filechooser {
+ height: 400px;
+ width: 600px;
+}
+
+.ares-filechooser-header {
@dod38fr Enyo JavaScript framework member
dod38fr added a note

why 2 classes with the same properties ?

@asnowfix Enyo JavaScript framework member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@dod38fr
Enyo JavaScript framework member

There's no attributions for the new icons. See this example of attribution

@dod38fr dod38fr commented on an outdated diff
ares/source/Ares.js
((134 lines not shown))
+ } 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");
@dod38fr Enyo JavaScript framework member
dod38fr added a note

maybe mention that's an internal error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@dod38fr dod38fr commented on an outdated diff
ares/source/Ares.js
((110 lines not shown))
+ },
+ 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) {
@dod38fr Enyo JavaScript framework member
dod38fr added a note

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@dod38fr dod38fr commented on the diff
@@ -427,6 +427,8 @@ var addr = argv.host;
app.configure(function(){
+ app.use(express.favicon(__dirname + '/ares/assets/images/ares_48x48.ico'));
@dod38fr Enyo JavaScript framework member
dod38fr added a note

__dirname is undef in node-webkit, use the myDir variable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@asnowfix asnowfix ENYO-2089: refresh the FileTree after `Save As…`
Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
dc8be21
@dod38fr dod38fr commented on an outdated diff
utilities/source/FileChooser.js
((55 lines not shown))
+ {name: "folderSelector", kind: "onyx.InputDecorator", classes: "onyx-toolbar-inline", components: [
+ {content: $L("Where") + ":", fit: true},
+ {name: "selectedFolder", kind: "onyx.Input", classes: "only-light", disabled: true, placeholder: $L("Folder")}
+ ]},
+ {name: "nameSelector", kind: "onyx.InputDecorator", classes: "onyx-toolbar-inline", showing: false, components: [
+ {content: $L("As") + ":", fit: true},
+ {name: "selectedName", kind: "onyx.Input", classes: "only-light", disabled: true, placeholder: $L("File"), selectOnFocus: true, onchange: "updateSelectedName"}
+ ]},
+ {name: "cancelButton", kind: "onyx.Button", classes: "onyx-negative", content: $L("Cancel"), ontap: "cancel"},
+ {name: "confirmButton", kind: "onyx.Button", classes: "onyx-affirmative", content: $L("OK"), ontap: "confirm"}
+ ]}
+ ]}
+ ],
+ events: {
+ /**
+ * Emitted once the end-user clicks cnacel or when a
@dod38fr Enyo JavaScript framework member
dod38fr added a note

typo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@asnowfix
Enyo JavaScript framework member

Just stacked dc8be21 fixing the auto-refresh issue.

@dod38fr dod38fr commented on the diff
utilities/source/FileChooser.js
((178 lines not shown))
+ this.hide() ;
+ if (this.debug) this.log("selectedFile:", this.selectedFile, "selectedName:", this.selectedName);
+ this.doFileChosen({
+ file: this.selectedFile,
+ name: (this.selectedName === this.selectedFile.name ? undefined : this.selectedName)
+ });
+ return true; // Stop event propagation
+ },
+ /** @private */
+ cancel: function(inSender, inEvent) {
+ if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
+ this.hide() ;
+ this.doFileChosen();
+ return true; // Stop event propagation
+ },
+ //FIXME: This is *nearly* identical to the code in Harmonia. Maybe move this into HermesFileTree?
@dod38fr Enyo JavaScript framework member
dod38fr added a note

In Enyo-1996, Harmonia is now a very thin shell. All the file and dir handling was moved in HermesFileTree

@asnowfix Enyo JavaScript framework member

To be adapted along when ENYO-1996 comes in, then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@asnowfix asnowfix ENYO-2089: review comment: add Ares icon attribution
- Also fix wiki formatting of former attribution (from open clipart)

Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
7c0f3dd
@asnowfix
Enyo JavaScript framework member

Added icon attribution: 7c0f3dd. We have a fairly large Palm/HP-owned set of icons with Ares 1. I prefer to not use external source as much as possible.

asnowfix added some commits
@asnowfix asnowfix ENYO-1020: fix review comment (typo)
Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
0b63dd1
@asnowfix asnowfix ENYO-1020: fix bug introduced while addressing review comment
- Use `refreshFile`, not `refreshFileTree`

Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
742da01
@asnowfix asnowfix ENYO-1020: address review comment (clarify)
- turn lambda function used in `async.waterfall` into local a nested one
  with a (hopefully descriptive) name `_prepareNewLocation`
- Use `refreshFile`, not `refreshFileTree`

Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
a846119
@asnowfix
Enyo JavaScript framework member

@dod38fr : review comments addressed. ready to merge.

@dod38fr dod38fr merged commit b853554 into master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 20, 2013
  1. @asnowfix

    ENYO-1020: editor: turn `Save` button into `File` menu…

    asnowfix committed
    - `File` menu has `Save`, `Save as` and `Close` menu items.
    
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  2. @asnowfix

    ENYO-1020: Fix typo in `EditorSettings` breaking the `chrome` theme

    asnowfix committed
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  3. @asnowfix

    ENYO-1020: `DirectorySelectorPopup` is now `FileChooser`

    asnowfix committed
    - `DirectorySelectorPopup` is now `Ares.FileChooser` defined by
      `utilities/source/FileChooser`
    - Move manual `style:`  into `Ares.css` as `.ares-filechooser*`
    
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
Commits on Mar 25, 2013
  1. @asnowfix
  2. @asnowfix

    ENYO-1020: Move top-level Ares MVC components under ares/source/

    asnowfix committed
    - the `model/` tree was not attached to one of the functional Ares
      components (Ares, Harmonia, Phobos, Deimos)
    
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  3. @asnowfix

    ENYO-2104: refresh Ares usage instructions

    asnowfix committed
    - git clone is no longer the primary way of delivering Ares
    
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  4. @asnowfix

    ENYO-1020: Move top-level Ares MVC components under ares/source/ (2/2)

    asnowfix committed
    - fix broken package.js
    
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  5. @asnowfix

    ENYO-1020: add /favicon.ico (avoid 404 in the logs...)

    asnowfix committed
    - remove former ares.png files fetched from the Net with random license
    - add icon from Ares1 (https://ares.palm.com) as favicon.ico
    
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  6. @asnowfix

    ENYO-2104: remove misleading runares.bat

    asnowfix committed
    - prefer to use NPM-generated wrappers
    
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
Commits on Mar 27, 2013
  1. @asnowfix

    ENYO-1020: add `ares.basename()` and `ares.dirname()` utilities

    asnowfix committed
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
Commits on Mar 28, 2013
  1. @dod38fr @asnowfix
Commits on Mar 29, 2013
  1. @dod38fr @asnowfix

    ENYO-1020: share waitPopup between Ares & Phobos

    dod38fr committed with asnowfix
    - Former implementation fires up one, the other one or both without
      a well-defined (or understandable) logic.
    - New implementation uses a single Ares#waitPopup that is usable via
      events by any module of Ares.
    
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  2. @asnowfix

    ENYO-1020: refactor FileChooser to be a filePicker or a folderPicker

    asnowfix committed
    - Still used by ProjectWizard (folderPicker)
    - Ready to be used by Phobos#saveAs (filePicker)
    
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  3. @asnowfix

    ENYO-1020: implement Phobos#saveAs

    asnowfix committed
    - UI interaction is handled by Phobos (text editor), which raises events
    - Events are trapped at the Ares level, which implements async file-
      system operations & report their success back to Phobos
    - FIXME: Phobos#saveAs() uses a common-JS type of completion callback
      (which is good) while Phobos#save() makes Ares directly call into
      Phobos's API (which is ugly, because Ares needs to know about an async
      operation completion public API which does not need to exist).
    - FIXME: saveAs popup does not show the folder where the current file
      is.  This is Ok in case of multiple saveAs (operation resumes in the
      same folder as before), but not for the first popup.
    
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  4. @asnowfix

    ENYO-1020: remove dead code (Documents.js)

    asnowfix committed
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  5. @asnowfix

    ENYO-1020: update FS protocol description, following @opopova comment

    asnowfix committed
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  6. @asnowfix
  7. @asnowfix

    ENYO-1020: decrease FileChooser tracing level.

    asnowfix committed
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  8. @asnowfix

    ENYO-2089: refresh the FileTree after `Save As…`

    asnowfix committed
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  9. @asnowfix

    ENYO-2089: review comment: add Ares icon attribution

    asnowfix committed
    - Also fix wiki formatting of former attribution (from open clipart)
    
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  10. @asnowfix

    ENYO-1020: fix review comment (typo)

    asnowfix committed
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  11. @asnowfix

    ENYO-1020: fix bug introduced while addressing review comment

    asnowfix committed
    - Use `refreshFile`, not `refreshFileTree`
    
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
  12. @asnowfix

    ENYO-1020: address review comment (clarify)

    asnowfix committed
    - turn lambda function used in `async.waterfall` into local a nested one
      with a (hopefully descriptive) name `_prepareNewLocation`
    - Use `refreshFile`, not `refreshFileTree`
    
    Enyo-DCO-1.1-Signed-off-by: Francois-Xavier KOWALSKI <francois-xavier.kowalski@hp.com>
View
42 README.md
@@ -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:
@@ -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:
@@ -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
@@ -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]
@@ -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_
View
25 ares/Ares.css
@@ -28,6 +28,24 @@ body {
}
/**/
+
+.ares-filechooser {
+ height: 400px;
+ width: 600px;
+}
+
+.ares-filechooser-header {
@dod38fr Enyo JavaScript framework member
dod38fr added a note

why 2 classes with the same properties ?

@asnowfix Enyo JavaScript framework member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ padding: 0 0.5em;
+ vertical-align: middle;
+}
+
+.ares-filechooser-footer {
+ padding: 0 0.5em;
+ vertical-align: middle;
+}
+
+/**/
+
.ares-groupbox-item-key {
padding: 0.5em;
}
@@ -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;
View
BIN ares/ares-128.png
Deleted file not rendered
View
BIN ares/ares-16.png
Deleted file not rendered
View
7 ares/assets/images/README.md
@@ -0,0 +1,7 @@
+* ares_48x48.png
+ * from Palm Ares1
+ * license: Apache 2
+* ares_48x48.ico
+ * converted from ares_48x48.png, using ImageMagick
+ * license: Apache 2
+
View
BIN ares/assets/images/ares_48x48.ico
Binary file not shown.
View
BIN ares/assets/images/ares_48x48.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
1 ares/package.js
@@ -5,7 +5,6 @@ enyo.depends(
"$lib/foss",
"source/",
"Ares.css",
- "../model/source",
"$lib/extra/analyzer2",
"../utilities/source",
"../services/source",
View
184 ares/source/Ares.js
@@ -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",
@@ -24,7 +24,7 @@ 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"}
@@ -32,7 +32,7 @@ enyo.kind({
handlers: {
onReloadServices: "handleReloadServices",
onUpdateAuth: "handleUpdateAuth",
- onShowWaitPopup: "handleShowWaitPopup",
+ onShowWaitPopup: "showWaitPopup",
onHideWaitPopup: "hideWaitPopup"
},
phobosViewIndex: 0,
@@ -71,65 +71,150 @@ 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="";
+ fileData = Ares.Workspace.files.newEntry(file, inContent, projectData);
+ self.switchToDocument(fileData);
}
- var id = Ares.Workspace.files.computeId(f);
- if (Ares.Workspace.files.get(id)) {
- alert("Duplicate File ID in cache!");
- }
- 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("Internal error: missing file/folder description"));
+ return;
+ }
+
+ async.waterfall([
+ this._closeDocument.bind(this, inEvent.docId),
+ _prepareNewLocation.bind(this),
+ this._saveDocument.bind(this, inEvent.content),
+ _savedToOpen.bind(this),
+ this._openDocument.bind(this, inEvent.projectData)
+ ], _footer);
+
+ function _prepareNewLocation(next) {
+ 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("Internal error: wrong file/folder description");
+ }
+ next(err, where);
+ }
+
+ 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();
@@ -282,11 +367,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() {
View
0 model/source/FileData.js → ares/source/FileData.js
File renamed without changes.
View
0 model/source/WorkspaceData.js → ares/source/WorkspaceData.js
File renamed without changes.
View
4 ares/source/package.js
@@ -1,4 +1,6 @@
enyo.depends(
"Ares.js",
- "DocumentToolbar.js"
+ "DocumentToolbar.js",
+ "FileData.js",
+ "WorkspaceData.js"
);
View
118 harmonia/source/Documents.js
@@ -1,118 +0,0 @@
-enyo.kind({
- name: "Documents",
- create: function() {
- this.documents = {};
- this.inherited(arguments);
- this.captureEvents();
- },
- destroy: function() {
- this.releaseEvents();
- this.inherited(arguments);
- },
- captureEvents: function() {
- this._captureHandler = enyo.bind(this, "captureHandler");
- document.addEventListener("keydown", this._captureHandler, true);
- },
- releaseEvents: function() {
- document.removeEventListener("keydown", this._captureHandler, true);
- },
- captureHandler: function(inEvent) {
- // Ctrl-S or Command/Win-S
- if ((inEvent.ctrlKey || inEvent.metaKey) && inEvent.keyCode == 83) {
- enyo.stopEvent(inEvent);
- if (this.activeDocument) {
- this.activeDocument.view.saveAction();
- }
- }
- },
- openDocument: function(inPath) {
- if (this.documents[inPath]) {
- this.activateDocument(this.documents[inPath]);
- } else {
- var d = this.prepareDocument(inPath);
- this.documents[inPath] = d;
- //
- d.view = this.findDocumentView(d);
- d.view.openDocument(d);
- //
- this.showDocument(d);
- this.getFile(inPath);
- }
- },
- prepareDocument: function(inPath) {
- var parts = inPath.split("/");
- var name = parts.pop();
- var ext = name.split(".").pop();
- var folder = parts.join("/");
- return {
- path: inPath,
- folder: folder,
- name: name,
- ext: ext,
- content: ""
- };
- },
- findDocumentView: function(inDocument) {
- // FIXME: brute force
- if (inDocument.name == "appinfo.json") {
- return this.$.appDocumentView;
- }
- if ({jpg:1, png:1, jpeg:1, gif:1}[inDocument.ext]) {
- return this.$.imageDocumentView;
- }
- if ({js:1}[inDocument.ext]) {
- return this.$.designerDocumentView;
- }
- /*
- if (inDocument.name.indexOf("chrome.js") >= 0) {
- return this.$.designerDocumentView;
- }
- */
- return this.$.textDocumentView;
- },
- showDocument: function(inDocument) {
- var index = this.$.basicCarousel.indexOfControl(inDocument.view) - 1;
- this.$.basicCarousel.snapTo(index, true);
- },
- getFile: function(inPath) {
- this.$.fileProvider.getFile(inPath).
- response(this, function(inSender, inContent) {
- var d = this.documents[inPath];
- if (d) {
- d.content = inContent;
- this.activateDocument(d);
- }
- })
- ;
- },
- activateDocument: function(inDocument) {
- if (this.activeDocument) {
- //this.activeDocument.deactivate();
- this.deactivateDocument(this.activeDocument);
- }
- this.activeDocument = inDocument;
- this.showDocument(inDocument);
- inDocument.view.activateDocument(inDocument);
- //inDocument.activate();
- },
- deactivateDocument: function(inDocument) {
- if (inDocument) {
- inDocument.view.deactivateDocument(inDocument);
- if (inDocument == this.activeDocument) {
- this.activeDocument = null;
- }
- }
- },
- saveDocument: function(inSender, inDocument) {
- this.log();
- this.$.fileProvider.putFile(inDocument.path, inDocument.content)
- .response(this, function() {
- //inDocument.dataSaved();
- })
- ;
- },
- closeDocument: function(inPath) {
- this.deactivateDocument(this.documents[inPath]);
- delete this.documents[inPath];
- }
-});
View
7 harmonia/source/Harmonia.js
@@ -88,6 +88,13 @@ enyo.kind({
});
r.go();
},
+ /**
+ * Refresh the {HermesFileTree} (if relevant), following a change of the given file
+ * @param {Object} changedFile
+ */
+ refreshFile: function(changedFile) {
+ this.$.hermesFileTree.refreshFile(changedFile);
+ },
delayedRefresh: function(msg) {
var onDone = new enyo.Async() ;
onDone.response(this, function(inSender, toSelectId) {
View
36 hermes/README.md
@@ -20,10 +20,10 @@ Hermes file-system providers use verbs that closely mimic the semantics defined
* `PROPFIND` lists properties of a resource. It recurses into the collections according to the `depth` parameter, which may be 0, 1, … etc plus `infinity`. For example, the following directory structure:
- $ tree 1/
- 1/
- ├── 0
- └── 1
+ $ tree dir1/
+ dir1/
+ ├── file0
+ └── file1
… corresponds to the following JSON object (multi-level node descriptor) returned by `PROPFIND`. The node descriptor Object format is defined by [this JSON schema](../assets/schema/com.enyojs.ares.fs.node.schema.json). The `path` property is node location absolute to the Hermes file-system server root: it uses URL notation: UNIX-type folder separator (`/`), not Windows-like (`\\`).
@@ -34,17 +34,25 @@ Hermes file-system providers use verbs that closely mimic the semantics defined
"name": "",
"children": [
{
- "isDir": false,
- "path": "/0",
- "name": "0",
- "id": "12efab780"
+ "isDir": true,
+ "path": "/dir1",
+ "name": "dir1",
+ "id": "12efa4560"
+ "children": [
+ {
+ "isDir": false,
+ "path": "/dir1/file0",
+ "name": "file0",
+ "id": "12efab780"
+ },
+ {
+ "isDir": false,
+ "path": "/dir1/file1",
+ "name": "file1",
+ "id": "0ae12ef56"
+ }
+ ]
},
- {
- "isDir": false,
- "path": "/1",
- "name": "1",
- "id": "0ae12ef56"
- }
],
"id": "934789346956340",
"versionTag": "af34ef45",
View
2 ide.js
@@ -427,6 +427,8 @@ var addr = argv.host;
app.configure(function(){
+ app.use(express.favicon(__dirname + '/ares/assets/images/ares_48x48.ico'));
@dod38fr Enyo JavaScript framework member
dod38fr added a note

__dirname is undef in node-webkit, use the myDir variable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
app.use('/ide', express.static(enyojsRoot + '/'));
app.use('/test', express.static(enyojsRoot + '/test'));
View
4 model/source/package.js
@@ -1,4 +0,0 @@
-enyo.depends(
- "FileData.js",
- "WorkspaceData.js"
-);
View
BIN phobos/assets/images/menu-icon-save.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN phobos/assets/images/menu-icon-stop.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
0 phobos/images/save-spinner.gif → phobos/assets/images/save-spinner.gif
File renamed without changes
View
2 phobos/source/EditorSettings.js
@@ -56,7 +56,7 @@ enyo.kind({
{name: "themes", kind: "onyx.Picker", onSelect: "themeSelected", components: [
{content: "ambiance", active: true},
{content: "chaos"},
- {content: "chrome "},
+ {content: "chrome"},
{content: "clouds"},
{content: "clouds_midnight"},
{content: "cobalt"},
View
118 phobos/source/Phobos.js
@@ -8,8 +8,24 @@ enyo.kind({
]},
{kind: "FittableRows", classes: "enyo-fit", Xstyle: "padding: 10px;", components: [
{kind: "onyx.Toolbar", layoutKind: "FittableColumnsLayout", components: [
- {name: "documentLabel", content: "Document"},
- {name: "saveButton", kind: "onyx.Button", content: $L("Save"), ontap: "saveDocAction"},
+ {kind: "onyx.MenuDecorator", onSelect: "fileMenuItemSelected", components: [
+ {content: "File"},
+ {kind: "onyx.Menu", components: [
+ {name: "saveButton", value: "saveDocAction", components: [
+ {kind: "onyx.IconButton", src: "$phobos/assets/images/menu-icon-save.png"},
+ {content: $L("Save")}
+ ]},
+ {name: "saveAsButton", value: "saveAsDocAction", components: [
+ {kind: "onyx.IconButton", src: "$phobos/assets/images/menu-icon-save.png"},
+ {content: $L("Save as...")}
+ ]},
+ {classes: "onyx-menu-divider"},
+ {name: "closeButton", value: "closeDocAction", components: [
+ {kind: "onyx.IconButton", src: "$phobos/assets/images/menu-icon-stop.png"},
+ {content: $L("Close")}
+ ]}
+ ]}
+ ]},
{name: "newKindButton", kind: "onyx.Button", Showing: "false", content: $L("New Kind"), ontap: "newKindAction"},
{fit: true},
{name: "editorButton", kind: "onyx.Button", content: "Editor Settings", ontap: "editorSettings"},
@@ -25,11 +41,8 @@ enyo.kind({
{name: "right", kind: "rightPanels", showing: false, arrangerKind: "CardArranger"}
]}
]},
- {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;"},
- {name: "waitPopupMessage", content: "Saving document...", style: "padding-top: 10px;"}
- ]},
{name: "savePopup", kind: "Ares.ActionPopup", onAbandonDocAction: "abandonDocAction"},
+ {name: "saveAsPopup", kind: "Ares.FileChooser", showing: false, headerText: $L("Save as..."), folderChooser: false, onFileChosen: "saveAsFileChosen"},
{name: "autocomplete", kind: "Phobos.AutoComplete"},
{name: "errorPopup", kind: "Ares.ErrorPopup", msg: "unknown error"},
{name: "findpop", kind: "FindPopup", centered: true, modal: true, floating: true, onFindNext: "findNext", onFindPrevious: "findPrevious", onReplace: "replace", onReplaceAll:"replaceAll", onHide: "focusEditor", onClose: "findClose", onReplaceFind: "replacefind"},
@@ -37,7 +50,10 @@ enyo.kind({
onChangeTheme: "changeTheme", onChangeHighLight: "changeHighLight", onClose: "closeEditorPop", onWordWrap: "changeWordWrap", onFontsizeChange: "changeFont", onTabSizsChange: "tabSize"}
],
events: {
+ onShowWaitPopup: "",
+ onHideWaitPopup: "",
onSaveDocument: "",
+ onSaveAsDocument: "",
onDesignDocument: "",
onCloseDocument: "",
onUpdate: ""
@@ -59,9 +75,16 @@ enyo.kind({
this.projectData.setProjectCtrl(this.projectCtrl);
}
},
- //
+ fileMenuItemSelected: function(inSender, inEvent) {
+ if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
+ if (typeof this[inEvent.selected.value] === 'function') {
+ this[inEvent.selected.value]();
+ } else {
+ this.warn("Unexpected event or missing function: event:", inEvent.selected.value);
+ }
+ },
saveDocAction: function() {
- this.showWaitPopup("Saving document...");
+ this.showWaitPopup($L("Saving ..."));
this.doSaveDocument({content: this.$.ace.getValue(), file: this.docData.getFile()});
},
saveComplete: function() {
@@ -77,8 +100,33 @@ enyo.kind({
this.log("Save failed: " + inMsg);
this.showErrorPopup("Unable to save the file");
},
- beginOpenDoc: function() {
- this.showWaitPopup("Opening document...");
+ saveAsDocAction: function() {
+ var file = this.docData.getFile();
+ this.$.saveAsPopup.setSelectedName(file.name);
+ this.$.saveAsPopup.show();
+ },
+ saveAsFileChosen: function(inSender, inEvent) {
+ if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
+
+ if (!inEvent.file) {
+ // no file or folder chosen
+ return;
+ }
+ var self = this;
+ this.showWaitPopup($L("Saving ..."));
+ this.doSaveAsDocument({
+ docId: this.docData.getId(),
+ projectData: this.projectData,
+ file: inEvent.file,
+ name: inEvent.name,
+ content: this.$.ace.getValue(),
+ next: function(err) {
+ self.hideWaitPopup();
+ if (typeof inEvent.next === 'function') {
+ inEvent.next();
+ }
+ }
+ });
},
openDoc: function(inDocData) {
// If we are changing documents, reparse any changes into the current projectIndexer
@@ -165,25 +213,52 @@ enyo.kind({
}
this.projectCtrl.buildProjectDb();
this.reparseAction(true);
- this.$.documentLabel.setContent(file.name);
this.docData.setEdited(edited);
this.$.toolbar.resized();
},
adjustPanelsForMode: function(mode) {
+ if (this.debug) this.log("mode:", mode);
// whether to show or not a panel, imageViewer and ace cannot be enabled at the same time
var showModes = {
- json: {imageViewer: false, ace: true , saveButton: true , newKindButton: false, designerButton: false, right: false },
- javascript: {imageViewer: false, ace: true , saveButton: true , newKindButton: true, designerButton: true , right: true },
- html: {imageViewer: false, ace: true , saveButton: true , newKindButton: false, designerButton: false, right: false },
- css: {imageViewer: false, ace: true , saveButton: true , newKindButton: false, designerButton: false, right: true },
- text: {imageViewer: false, ace: true , saveButton: true , newKindButton: false, designerButton: false, right: false },
- image: {imageViewer: true , ace: false, saveButton: false, newKindButton: false, designerButton: false, right: false }
+ javascript: {
+ imageViewer: false,
+ ace: true,
+ saveButton: true,
+ saveAsButton: true,
+ newKindButton: true,
+ designerButton: true,
+ right: true
+ },
+ image: {
+ imageViewer: true,
+ ace: false,
+ saveButton: false,
+ saveAsButton: false,
+ newKindButton: false,
+ designerButton: false,
+ right: false
+ },
+ text: {
+ imageViewer: false,
+ ace: true,
+ saveButton: true,
+ saveAsButton: true,
+ newKindButton: false,
+ designerButton: false,
+ right: false
+ }
};
- var showSettings = showModes[mode]||showModes['text'];
+ var showStuff, showSettings = showModes[mode]||showModes['text'];
for (var stuff in showSettings) {
- this.$[stuff].setShowing( showSettings[stuff] ) ;
+ showStuff = showSettings[stuff];
+ if (this.debug) this.log("show", stuff, ":", showStuff);
+ if (typeof this.$[stuff].setShowing === 'function') {
+ this.$[stuff].setShowing(showStuff) ;
+ } else {
+ this.warn("BUG: attempting to show/hide a non existing element: ", stuff);
+ }
}
// xxxIndex: specify what to show in the "RightPanels" kinds (declared at the end of this file)
@@ -203,11 +278,10 @@ enyo.kind({
return showSettings.ace ;
},
showWaitPopup: function(inMessage) {
- this.$.waitPopupMessage.setContent(inMessage);
- this.$.waitPopup.show();
+ this.doShowWaitPopup({msg: inMessage});
},
hideWaitPopup: function() {
- this.$.waitPopup.hide();
+ this.doHideWaitPopup();
},
showErrorPopup : function(msg) {
this.$.errorPopup.setErrorMsg(msg);
View
6 project-view/assets/images/README.md
@@ -1,4 +1,4 @@
* icon project_preview.png:
-* * resized from `/usr/share/openclipart/png/tools/ruota_dentata_architetto_01.png`
-* * provided by [openclipart](http://www.openclipart.org) project
-* * license: "creative commons Public Domain Dedication"
+ * resized from `/usr/share/openclipart/png/tools/ruota_dentata_architetto_01.png`
+ * provided by [openclipart](http://www.openclipart.org) project
+ * license: "creative commons Public Domain Dedication"
View
87 project-view/source/DirectorySelector.js
@@ -1,87 +0,0 @@
-enyo.kind({
- name: "SelectDirectoryPopup",
- kind: "onyx.Popup",
- modal: true,
- centered: true,
- floating: true,
- autoDismiss: false,
- debug: false,
- published: {
- headerText: ''
- },
- headerTextChanged: function () {
- this.$.header.setContent(this.headerText);
- },
- components: [
- {kind: "FittableRows", style: "height: 400px; width: 600px", components: [
- {kind: "Control", tag: "span", style: "padding: 0 4px; vertical-align: middle;", content: "Select a directory", name: "header"},
- {kind: "FittableColumns", content: "fittableColumns", fit: true, components: [
- {kind: "ProviderList", selector: ["type", "filesystem"], name: "providerList", header: "Sources", onSelectProvider: "handleSelectProvider"},
- {kind: "HermesFileTree", fit: true, name: "hermesFileTree", onFileClick: "selectFile", onFolderClick: "selectFolder", onNewFolderConfirm: "createFolder"}
- ]},
- {kind: "FittableColumns", content: "fittableColumns2", isContainer: true, components: [
- {kind: "Control", content: "Selected: ", fit: true, name: "selectedDir"},
- {kind: "onyx.Button", classes: "onyx-negative", content: "Cancel", ontap: "cancel"},
- {kind: "onyx.Button", classes: "onyx-affirmative", content: "OK", isContainer: true, name: "confirm", ontap: "confirmTap"}
- ]}
- ]}
- ],
- events: {
- onDirectorySelected: "",
- onDone: ""
- },
- selectedDir: undefined,
- create: function() {
- this.inherited(arguments);
- this.$.hermesFileTree.hideFileOpButtons();
- },
- handleSelectProvider: function(inSender, inEvent) {
- if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
- if (inEvent.service) {
- this.$.hermesFileTree
- .connectService(inEvent.service)
- .refreshFileTree(null, null, inEvent.callBack);
- }
- return true; //Stop event propagation
- },
- selectFile: function(inSender, inEvent) {
- if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
- this.selectedDir = undefined;
- this.$.selectedDir.setContent("Selected: ");
- this.$.confirm.setDisabled(true);
- return true; // Stop event propagation
- },
- selectFolder: function(inSender, inEvent) {
- if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
- this.selectedDir = inEvent.file;
- this.$.selectedDir.setContent("Selected: " + this.selectedDir.path);
- this.$.confirm.setDisabled(false);
- return true; // Stop event propagation
- },
- confirmTap: function(inSender, inEvent) {
- if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
- this.doDirectorySelected({serviceId: this.selectedServiceId, directory: this.selectedDir});
- return true; // Stop event propagation
- },
- cancel: function() {
- this.hide() ;
- this.doDone(); // inform owner
- },
- //FIXME: This is *nearly* identical to the code in Harmonia. Maybe move this into HermesFileTree?
- createFolder: function(inSender, inEvent) {
- var folderId = inEvent.folderId;
- var name = inEvent.fileName.trim();
- var service = this.selectedDir.service;
- if (this.debug) this.log("Creating new folder "+name+" into folderId="+folderId);
- service.createFolder(folderId, name)
- .response(this, function(inSender, inResponse) {
- if (this.debug) this.log("Response: "+inResponse);
- this.$.hermesFileTree.refreshFileTree(null, inResponse);
- })
- .error(this, function(inSender, inError) {
- if (this.debug) this.log("Error: "+inError);
- this.$.hermesFileTree.showErrorPopup("Creating folder "+name+" failed:" + inError);
- });
- }
-});
-
View
7 project-view/source/ProjectView.js
@@ -44,6 +44,13 @@ enyo.kind({
showErrorPopup : function(msg, details) {
this.$.errorPopup.raise(msg, details);
},
+ /**
+ * Refresh the {ProjectView} (if relevant), following a change of the given file
+ * @param {Object} changedFile
+ */
+ refreshFile: function(changedFile) {
+ this.$.harmonia.refreshFile(changedFile);
+ },
scanProjectAction: function(inSender, inEvent) {
this.$.projectWizardScan.setHeaderText('Select a directory containing one or more project.json files');
this.$.projectWizardScan.show();
View
31 project-view/source/ProjectWizard.js
@@ -13,7 +13,7 @@ enyo.kind({
onHideWaitPopup: ""
},
handlers: {
- onDirectorySelected: "prepareShowProjectPropPopup",
+ onFileChosen: "prepareShowProjectPropPopup",
onModifiedConfig: "createProject" ,
// can be canceled by either of the included components
onDone: "hideMe"
@@ -21,7 +21,7 @@ enyo.kind({
components: [
{kind: "ProjectProperties", name: "propertiesWidget"},
- {kind: "SelectDirectoryPopup", canGenerate: false, name: "selectDirectoryPopup"},
+ {kind: "Ares.FileChooser", canGenerate: false, name: "selectDirectoryPopup", folderChooser: true},
{kind: "Ares.ErrorPopup", name: "errorPopup", msg: "unknown error"}
],
debug: false,
@@ -46,10 +46,14 @@ enyo.kind({
// Step 2: once the directory is selected by user, show the project properties popup
// Bail out if a project.json file already exists
prepareShowProjectPropPopup: function(inSender, inEvent) {
+ if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
+ if (!inEvent.file) {
+ this.hideMe();
+ return;
+ }
var propW = this.$.propertiesWidget;
- this.selectedServiceId = inEvent.serviceId;
- this.selectedDir = inEvent.directory;
+ this.selectedDir = inEvent.file;
propW.setupCreate();
propW.setTemplateList([]); // Reset template list
@@ -265,8 +269,7 @@ enyo.kind({
this.doAddProjectInList({
name: this.projectName,
folderId: this.selectedDir.id,
- service: this.selectedDir.service,
- serviceId: this.selectedServiceId
+ service: this.selectedDir.service
});
},
@@ -345,7 +348,7 @@ enyo.kind({
*/
enyo.kind({
name: "ProjectWizardScan",
- kind: "SelectDirectoryPopup",
+ kind: "Ares.FileChooser",
modal: true,
centered: true,
floating: true,
@@ -356,7 +359,7 @@ enyo.kind({
onAddProjectInList: ""
},
handlers: {
- onDirectorySelected: "searchProjects"
+ onFileChosen: "searchProjects"
},
debug: false,
@@ -379,15 +382,19 @@ enyo.kind({
this.doAddProjectInList({
name: projectData.name || parentDir.name,
folderId: parentDir.id,
- service: this.selectedDir.service,
- serviceId: this.selectedServiceId
+ service: this.selectedDir.service
});
});
},
searchProjects: function (inSender, inEvent) {
- var folderId = inEvent.directory.id ;
- var service = inEvent.directory.service;
+ if (!inEvent.file) {
+ this.hide();
+ return;
+ }
+
+ var folderId = inEvent.file.id ;
+ var service = inEvent.file.service;
var hft = this.$.hermesFileTree ;
View
1 project-view/source/package.js
@@ -1,6 +1,5 @@
enyo.depends(
"ProjectList.js",
- "DirectorySelector.js",
"ProjectWizard.js",
"ProjectView.js",
"ProjectConfig.js",
View
3 runares.bat
@@ -1,3 +0,0 @@
-REM launch node server which will launch browser on Ares
-start node.exe ide.js -b
-
View
18 services/source/HermesFileTree.js
@@ -422,6 +422,15 @@ enyo.kind({
}
};
},
+ /**
+ * Refresh the current {HermesFileTree} view, if applicable
+ * @param {Object} changedFile
+ */
+ refreshFile: function(changedFile) {
+ // FIXME: not cleanly implemented: should check wether
+ // a refresh is necessary first.
+ this.refreshFileTree();
+ },
// All parameters are optional.
// - node is null for the "top" refresh call. Node is also used for inner (async)
@@ -497,6 +506,15 @@ enyo.kind({
}
return folder;
},
+
+ /**
+ * @public
+ * Returns a file data structure for the parent node of the currently selected node
+ */
+ getParentOfSelected: function() {
+ return this.selectedNode.container.file; // is a folder...
+ },
+
// User Interaction for New File op
newFileClick: function(inSender, inEvent) {
if (this.debug) this.log(inSender, "=>", inEvent);
View
2 test/testrunner/tests/ProjectViewTest.js
@@ -67,7 +67,7 @@ enyo.kind({
if (this.debug) enyo.log("testHandleSelectProvider: handleSelectProvider called") ;
dirPopup.handleSelectProvider(this, {service: myService, callBack: userSelectDir});
} else {
- this.finish("SelectDirectoryPopup: "+this.aresObj.$.projectView.$.projectWizardCreate.$.SelectDirectoryPopup+ " is not available!");
+ this.finish("Ares.FileChooser: "+this.aresObj.$.projectView.$.projectWizardCreate.$.selectDirectoryPopup+ " is not available!");
}
},
statics: {
View
211 utilities/source/FileChooser.js
@@ -0,0 +1,211 @@
+enyo.kind({
+ name: "Ares.FileChooser",
+ kind: "onyx.Popup",
+ modal: true,
+ centered: true,
+ floating: true,
+ autoDismiss: false,
+ debug: false,
+ published: {
+ /**
+ * When true (the default), allow to pick only a
+ * folder (the "Ok" button is active when a folder is
+ * selected). Otherwise, allow only to pick a file
+ * (the "Ok" button is active either when a file is
+ * selected or when a folder is selected and the file
+ * name input field is manually filled.).
+ */
+ folderChooser: true,
+ /**
+ * Popup header. Defaults to "Select a File" or
+ * "Select a Folder" depending on the value of
+ * {Ares.FileChooser#folderChooser}.
+ */
+ headerText: '',
+ /**
+ * When true the {Ares.FileChooser} has a "New Folder"
+ * button
+ */
+ allowCreateFolder: true,
+ /**
+ * When true the {Ares.FileChooser} offers to define a
+ * new (not yet exiting) file name. This property is
+ * applicable only if {Ares.FileChooser#folderChooser}
+ * is false.
+ */
+ allowNewFile: true,
+ /**
+ * File name to use for the selection. Has visible
+ * effects only when {Ares.FileChooser#folderChooser}
+ * is true.
+ */
+ selectedName: ""
+ },
+ headerTextChanged: function () {
+ this.$.header.setContent(this.headerText);
+ },
+ components: [
+ {kind: "FittableRows", classes: "onyx-popup ares-filechooser", components: [
+ {kind: "Control", tag: "span", classes: "ares-title ares-filechooser-header", content: "Select a directory", name: "header"},
+ {kind: "FittableColumns", classes: "onyx-light", fit: true, components: [
+ {kind: "ProviderList", selector: ["type", "filesystem"], name: "providerList", header: "Toto", onSelectProvider: "handleSelectProvider"},
+ {kind: "HermesFileTree", fit: true, name: "hermesFileTree", onFileClick: "_selectFile", onFolderClick: "_selectFolder", onNewFolderConfirm: "createFolder"}
+ ]},
+ {kind: "FittableColumns", classes: "onyx-light ares-filechooser-footer", isContainer: true, components: [
+ {name: "folderSelector", kind: "onyx.InputDecorator", classes: "onyx-toolbar-inline", components: [
+ {content: $L("Where") + ":", fit: true},
+ {name: "selectedFolder", kind: "onyx.Input", classes: "only-light", disabled: true, placeholder: $L("Folder")}
+ ]},
+ {name: "nameSelector", kind: "onyx.InputDecorator", classes: "onyx-toolbar-inline", showing: false, components: [
+ {content: $L("As") + ":", fit: true},
+ {name: "selectedName", kind: "onyx.Input", classes: "only-light", disabled: true, placeholder: $L("File"), selectOnFocus: true, onchange: "updateSelectedName"}
+ ]},
+ {name: "cancelButton", kind: "onyx.Button", classes: "onyx-negative", content: $L("Cancel"), ontap: "cancel"},
+ {name: "confirmButton", kind: "onyx.Button", classes: "onyx-affirmative", content: $L("OK"), ontap: "confirm"}
+ ]}
+ ]}
+ ],
+ events: {
+ /**
+ * Emitted once the end-user clicks cancel or when a
+ * file/folder is chosen.
+ *
+ * If none is chosen (the end-user tapped "Cancel"),
+ * this event does not contain the {file} property.
+ *
+ * If a folder is chosen, the event contains the
+ * {file} property, itself having a true {isDir}
+ * property.
+ *
+ * If a file is chosen, one of the below is true:
+ *
+ * 1. {event#file} exists, {event#file#isDir} is false
+ * and {event#name} is falsy: the user selected the
+ * existing file {event#file}.
+ *
+ * 2. {event#file} exists, {event#file#isDir} is true
+ * and the {event#name} is set: The file {event#name}
+ * is to be created in the folder {event#file}
+ *
+ * 3. {event#file} exists, {event#file#isDir} is false
+ * and {event#name} is set: the file {event#name} is
+ * to be created in the same folder as the file
+ * {event#file}
+ */
+ onFileChosen: ""
+ },
+ create: function() {
+ this.inherited(arguments);
+ if (!this.headerText) {
+ if (this.folderChooser) {
+ this.setHeaderText($L("Select a Folder"));
+ } else {
+ this.setHeaderText($L("Select a File"));
+ }
+ }
+ if (!this.folderChooser) {
+ this.$.nameSelector.show();
+ if (this.allowNewFile) {
+ this.$.selectedName.setDisabled(false);
+ }
+ }
+ this.$.header.setContent(this.headerText);
+ this.$.hermesFileTree.hideFileOpButtons();
+ },
+ selectedNameChanged: function(oldSelectedName) {
+ if (this.debug) this.log("old:", oldSelectedName, " -> new:", this.selectedName);
+ this.$.selectedName.setValue(this.selectedName);
+ this.updateConfirmButton();
+ },
+ handleSelectProvider: function(inSender, inEvent) {
+ if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
+ if (inEvent.service) {
+ this.$.hermesFileTree
+ .connectService(inEvent.service)
+ .refreshFileTree(null, null, inEvent.callBack);
+ }
+ return true; //Stop event propagation
+ },
+ /** @private */
+ _selectFile: function(inSender, inEvent) {
+ if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
+ if (this.folderChooser) {
+ // TODO: should rather
+ // selectedFile.parentId... but this node
+ // property does not exist in Ares filesystems
+ // (yet)
+ this.selectedFile = undefined;
+ } else {
+ this.selectedFile = inEvent.file;
+ this.selectedFile.parent = this.$.hermesFileTree.getParentOfSelected();
+ this.$.confirmButton.setDisabled(false);
+ }
+ this.$.selectedFolder.setValue(ares.basename(ares.dirname(inEvent.file.path)));
+ this.setSelectedName(inEvent.file.name);
+ return true; // Stop event propagation
+ },
+ /** @private */
+ _selectFolder: function(inSender, inEvent) {
+ if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
+ // do neither modify this.selectedName nor
+ // this.$.selectedName.value
+ this.selectedFile = inEvent.file;
+ this.selectedFile.parent = this.$.hermesFileTree.getParentOfSelected();
+ if (this.folderChooser) {
+ this.$.confirmButton.setDisabled(false);
+ } else {
+ this.$.confirmButton.setDisabled(true);
+ }
+ this.$.selectedFolder.setValue(inEvent.file.name);
+ this.updateConfirmButton();
+ return true; // Stop event propagation
+ },
+ updateSelectedName: function(inSender, inEvent) {
+ if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
+ this.$.confirmButton.setDisabled(false);
+ this.setSelectedName(inSender.getValue());
+ },
+ updateConfirmButton: function() {
+ if (this.folderChooser) {
+ this.$.confirmButton.setDisabled(!(this.selectedFile && this.selectedFile.isDir));
+ } else {
+ this.$.confirmButton.setDisabled(!(this.selectedFile && this.selectedName));
+ }
+ },
+ /** @private */
+ confirm: function(inSender, inEvent) {
+ if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
+ this.hide() ;
+ if (this.debug) this.log("selectedFile:", this.selectedFile, "selectedName:", this.selectedName);
+ this.doFileChosen({
+ file: this.selectedFile,
+ name: (this.selectedName === this.selectedFile.name ? undefined : this.selectedName)
+ });
+ return true; // Stop event propagation
+ },
+ /** @private */
+ cancel: function(inSender, inEvent) {
+ if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
+ this.hide() ;
+ this.doFileChosen();
+ return true; // Stop event propagation
+ },
+ //FIXME: This is *nearly* identical to the code in Harmonia. Maybe move this into HermesFileTree?
@dod38fr Enyo JavaScript framework member
dod38fr added a note

In Enyo-1996, Harmonia is now a very thin shell. All the file and dir handling was moved in HermesFileTree

@asnowfix Enyo JavaScript framework member

To be adapted along when ENYO-1996 comes in, then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ createFolder: function(inSender, inEvent) {
+ if (this.debug) this.log("sender:", inSender, ", event:", inEvent);
+ var folderId = inEvent.folderId;
+ var name = inEvent.fileName.trim();
+ var service = this.selectedFile.service;
+ if (this.debug) this.log("Creating new folder:", name, "into folderId:", folderId, "under service:", service);
+ service.createFolder(folderId, name)
+ .response(this, function(inSender, inResponse) {
+ if (this.debug) this.log("Response: "+inResponse);
+ this.$.hermesFileTree.refreshFileTree(null, inResponse);
+ })
+ .error(this, function(inSender, inError) {
+ if (this.debug) this.log("Error: "+inError);
+ this.$.hermesFileTree.showErrorPopup("Creating folder "+name+" failed:" + inError);
+ });
+ }
+});
+
View
16 utilities/source/lang.js
@@ -40,6 +40,22 @@ var ares = {
return dst;
},
/**
+ * Extract the filename of the given path
+ * @param {String} the path to extract the basename from
+ * @return the path basename
+ */
+ basename: function(path) {
+ return path.replace(/\\/g,'/').replace( /.*\//, '' );
+ },
+ /**
+ * Extract the containing folder of the given path
+ * @param {String} the path to extract the dirname from
+ * @return the path dirname
+ */
+ dirname: function (path) {
+ return path.replace(/\\/g,'/').replace(/\/[^\/]*$/, '');;
+ },
+ /**
* Decode an 'application/x-www-urlencoded' string into an {Object}
*
* @param {String} s the string to parse
View
3 utilities/source/package.js
@@ -5,5 +5,6 @@ enyo.depends(
"ErrorPopup.js",
"AsyncError.js",
"IFrame.js",
- "LocalStorage.js"
+ "LocalStorage.js",
+ "FileChooser.js"
);
Something went wrong with that request. Please try again.