diff --git a/Gruntfile.js b/Gruntfile.js index 708119c..fccf38b 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -4,7 +4,7 @@ var path = require('path'); module.exports = function(grunt) { - var NW_VERSION = '0.12.2'; + var NW_VERSION = '0.12.3'; var BUILD_DIR = 'build'; var BUILD_TARGETS = { linux_ia32: true, diff --git a/css/style.css b/css/style.css index 50c64db..63e9fea 100644 --- a/css/style.css +++ b/css/style.css @@ -77,7 +77,8 @@ html, body { transition: 150ms linear; position: relative; overflow: hidden; - min-width: 150px; + width: 125px; + height: 125px; } .launcher li.app-item::after { @@ -105,6 +106,11 @@ html, body { display: block; text-align: center; color: white; + white-space: nowrap; + text-overflow: ellipsis; + max-width: 90%; + overflow: hidden; + margin: auto; } /* Edit View */ @@ -116,6 +122,14 @@ html, body { flex-direction: column; } +.edit .menu-bar { + padding: 5px 10px; +} + +.edit .menu-bar button { + margin-right: 3px; +} + .edit .workspace { display: flex; flex-direction: row; @@ -136,6 +150,10 @@ html, body { flex: 2; } +.edit .item-form > form { + width: 100%; +} + .edit .apps-list .icon-theme-selector > select { width: 100%; } diff --git a/js/components/edit/edit-view.jsx b/js/components/edit/edit-view.jsx index dcea0a2..50a8952 100644 --- a/js/components/edit/edit-view.jsx +++ b/js/components/edit/edit-view.jsx @@ -4,6 +4,7 @@ var ProfileTree = require('./profile-tree.jsx'); var DesktopAppList = require('./desktop-app-list.jsx'); var ItemForm = require('./item-form.jsx'); var IconThemeSelector = require('./icon-theme-selector.jsx'); +var ProfileMenu = require('./profile-menu.jsx'); var tree = require('../../util/tree'); var actions = require('../../store/actions'); @@ -21,7 +22,7 @@ var EditView = React.createClass({ return (
- +
diff --git a/js/components/edit/profile-menu.jsx b/js/components/edit/profile-menu.jsx new file mode 100644 index 0000000..e5a0586 --- /dev/null +++ b/js/components/edit/profile-menu.jsx @@ -0,0 +1,79 @@ +var React = require('react'); +var connect = require('react-redux').connect; +var actions = require('../../store/actions'); + +var ProfileMenu = React.createClass({ + + render: function() { + + return ( +
+ + + +
+ ); + + }, + + handleOpenClick: function() { + var dispatch = this.props.dispatch; + this.showFileDialog() + .then(function(profilePath) { + dispatch(actions.common.loadProfile(profilePath)); + }) + ; + }, + + handleSaveClick: function() { + + var dispatch = this.props.dispatch; + var profile = this.props.profile; + var profilePath = this.props.profilePath; + + var promise = profilePath ? Promise.resolve(profilePath) : this.showFileDialog(true); + + promise.then(function(profilePath) { + dispatch(actions.edit.saveProfile(profilePath, profile)); + }); + + }, + + showFileDialog: function(saveAs) { + + var fileInput = this.refs.fileInput.getDOMNode(); + + // Toggle 'save as' feature + if(saveAs) { + fileInput.nwsaveas = true; + } else { + fileInput.removeAttribute('nwsaveas'); + } + + return new Promise(function(resolve, reject) { + + fileInput.addEventListener('change', handleChange, false); + fileInput.click(); + + function handleChange(evt) { + fileInput.removeEventListener('change', handleChange); + var value = this.value; + this.value = null; + resolve(value); + } + + }); + + + } + +}); + +function select(state) { + return { + profile: state.profile, + profilePath: state.profilePath + }; +} + +module.exports = connect(select)(ProfileMenu); diff --git a/js/components/edit/profile-tree.jsx b/js/components/edit/profile-tree.jsx index c4bb491..3e870b7 100644 --- a/js/components/edit/profile-tree.jsx +++ b/js/components/edit/profile-tree.jsx @@ -50,10 +50,6 @@ var TreeNode = React.createClass({ var ProfileTree = React.createClass({ - componentDidMount: function() { - this.props.dispatch(actions.common.loadProfile('./default-profile.json')); - }, - render: function() { return ( diff --git a/js/store/actions/common.js b/js/store/actions/common.js index edcc659..c3002a9 100644 --- a/js/store/actions/common.js +++ b/js/store/actions/common.js @@ -10,7 +10,7 @@ exports.loadProfile = function(profilePath) { dispatch({ type: LOAD_PROFILE, profilePath: profilePath }); - return Util.System.loadJSONFile(profilePath) + return Util.System.loadJSON(profilePath) .then(function(profile) { dispatch({ type: LOAD_PROFILE_SUCCESS, profile: profile }); return profile; diff --git a/js/store/actions/edit.js b/js/store/actions/edit.js index 1ea1439..a8a88b2 100644 --- a/js/store/actions/edit.js +++ b/js/store/actions/edit.js @@ -39,10 +39,19 @@ exports.loadDesktopApps = function() { }; }; -exports.saveProfile = function(profile) { +exports.saveProfile = function(destPath, profile) { return function(dispatch, getState) { - + dispatch({ type: SAVE_PROFILE, profile: profile, path: destPath }); + + return Util.System.saveJSON(destPath, profile) + .then(function() { + dispatch({ type: SAVE_PROFILE_SUCCESS, profile: profile, path: destPath }); + }) + .catch(function(err) { + dispatch({ type: SAVE_PROFILE_FAILED, error: err }); + }) + ; }; }; diff --git a/js/store/actions/launcher.js b/js/store/actions/launcher.js index 4c5e131..cf9eded 100644 --- a/js/store/actions/launcher.js +++ b/js/store/actions/launcher.js @@ -10,7 +10,7 @@ exports.runApp = function(execPath) { dispatch({ type: RUN_APP, execPath: execPath }); - return Util.System.runApp(execPath) + return Util.System.runApp(execPath, { clearFreeDesktopFlags: true }) .then(function() { dispatch({ type: RUN_APP_SUCCESS, execPath: execPath }); return execPath; diff --git a/js/util/system.js b/js/util/system.js index 92cda9d..0e7688d 100644 --- a/js/util/system.js +++ b/js/util/system.js @@ -10,7 +10,7 @@ var Cache = require('./cache'); * @param filePath The path of the json file * @return Promise */ -exports.loadJSONFile = function(filePath) { +exports.loadJSON = function(filePath) { return new Promise(function(resolve, reject) { fs.readFile(filePath, 'utf8', function(err, fileContent) { if(err) return reject(err); @@ -24,6 +24,19 @@ exports.loadJSONFile = function(filePath) { }); }; +exports.saveJSON = function(filePath, obj) { + + var jsonStr = JSON.stringify(obj, null, 2); + + return new Promise(function(resolve, reject) { + fs.writeFile(filePath, jsonStr, function(err) { + if(err) return reject(err); + return resolve(); + }); + }); + +}; + /** * Load a INI file * @@ -44,7 +57,18 @@ exports.loadINIFile = function(filePath) { }); }; -exports.runApp = function(execPath) { +exports.clearFreeDesktopFlags = function(exec) { + return exec.replace(/%[uUdDfFnNickvm]/g, ''); +}; + +exports.runApp = function(execPath, opts) { + + opts = opts || {}; + + if(opts.clearFreeDesktopFlags) { + execPath = exports.clearFreeDesktopFlags(execPath); + } + return new Promise(function(resolve, reject) { cp.exec(execPath, function(err) { if(err) return reject(err);