Base chargement des icons des applications
This commit is contained in:
parent
f61ac744a9
commit
bd5d41aa88
|
@ -48,7 +48,6 @@ html, body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.launcher ul.apps-list {
|
.launcher ul.apps-list {
|
||||||
display: block;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -105,17 +104,27 @@ html, body {
|
||||||
|
|
||||||
/* Edit View */
|
/* Edit View */
|
||||||
|
|
||||||
|
.edit {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
.edit ul.desktop-apps {
|
.edit ul.desktop-apps {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit li.desktop-app {
|
.edit li.desktop-app {
|
||||||
height: 30px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit img.desktop-app-icon {
|
.edit img.desktop-app-icon {
|
||||||
height: 30px;
|
height: 50px;
|
||||||
|
width: 50px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?><svg width='50px' height='50px' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="uil-hourglass"><rect x="0" y="0" width="100" height="100" fill="none" class="bk"></rect><g><path fill="none" stroke="#ffffff" stroke-width="5" stroke-miterlimit="10" d="M58.4,51.7c-0.9-0.9-1.4-2-1.4-2.3s0.5-0.4,1.4-1.4 C70.8,43.8,79.8,30.5,80,15.5H70H30H20c0.2,15,9.2,28.1,21.6,32.3c0.9,0.9,1.4,1.2,1.4,1.5s-0.5,1.6-1.4,2.5 C29.2,56.1,20.2,69.5,20,85.5h10h40h10C79.8,69.5,70.8,55.9,58.4,51.7z" class="glass"></path><clipPath id="uil-hourglass-clip1"><rect x="15" y="20" width="70" height="25" class="clip"><animate attributeName="height" from="25" to="0" dur="1s" repeatCount="indefinite" vlaues="25;0;0" keyTimes="0;0.5;1"></animate><animate attributeName="y" from="20" to="45" dur="1s" repeatCount="indefinite" vlaues="20;45;45" keyTimes="0;0.5;1"></animate></rect></clipPath><clipPath id="uil-hourglass-clip2"><rect x="15" y="55" width="70" height="25" class="clip"><animate attributeName="height" from="0" to="25" dur="1s" repeatCount="indefinite" vlaues="0;25;25" keyTimes="0;0.5;1"></animate><animate attributeName="y" from="80" to="55" dur="1s" repeatCount="indefinite" vlaues="80;55;55" keyTimes="0;0.5;1"></animate></rect></clipPath><path d="M29,23c3.1,11.4,11.3,19.5,21,19.5S67.9,34.4,71,23H29z" clip-path="url(#uil-hourglass-clip1)" fill="#d2d2d2" class="sand"></path><path d="M71.6,78c-3-11.6-11.5-20-21.5-20s-18.5,8.4-21.5,20H71.6z" clip-path="url(#uil-hourglass-clip2)" fill="#d2d2d2" class="sand"></path><animateTransform attributeName="transform" type="rotate" from="0 50 50" to="180 50 50" repeatCount="indefinite" dur="1s" values="0 50 50;0 50 50;180 50 50" keyTimes="0;0.7;1"></animateTransform></g></svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -4,24 +4,38 @@ var AppItem = require('./app-item.jsx');
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
|
|
||||||
|
// The app items to display in the list
|
||||||
items: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
|
items: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
|
||||||
|
|
||||||
|
// the parent item path
|
||||||
parentPath: React.PropTypes.oneOfType([
|
parentPath: React.PropTypes.oneOfType([
|
||||||
React.PropTypes.string,
|
React.PropTypes.string,
|
||||||
React.PropTypes.arrayOf(React.PropTypes.number)
|
React.PropTypes.arrayOf(React.PropTypes.number)
|
||||||
]).isRequired,
|
]).isRequired,
|
||||||
|
|
||||||
|
// Item click handler
|
||||||
onItemClick: React.PropTypes.func.isRequired,
|
onItemClick: React.PropTypes.func.isRequired,
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
|
||||||
var parentPath = this.props.parentPath;
|
var parentPath = this.props.parentPath;
|
||||||
|
|
||||||
|
// For each items, we create an AppItem component
|
||||||
var items = (this.props.items).map(function(item, i) {
|
var items = (this.props.items).map(function(item, i) {
|
||||||
|
|
||||||
|
// The item path identifier
|
||||||
var path = parentPath+'.'+i;
|
var path = parentPath+'.'+i;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppItem key={path} itemPath={path} item={item} onItemClick={this.props.onItemClick} />
|
<AppItem key={path} itemPath={path} item={item} onItemClick={this.props.onItemClick} />
|
||||||
);
|
);
|
||||||
|
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
|
// Create the apps list
|
||||||
return (
|
return (
|
||||||
<ul key={parentPath} className="apps-list">
|
<ul key={parentPath} className="apps-list">
|
||||||
{items}
|
{items}
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var Util = require('../util');
|
var Util = require('../util');
|
||||||
|
var LazyLoad = require('./mixins/lazy-load');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
|
|
||||||
|
mixins: [LazyLoad],
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return { icon: '' };
|
return { icon: 'img/hourglass.svg', loading: false };
|
||||||
|
},
|
||||||
|
|
||||||
|
onInViewport: function() {
|
||||||
|
if(!this.state.loading) {
|
||||||
|
this.setState({ loading: true });
|
||||||
|
var desktopEntry = this.props.desktopEntry;
|
||||||
|
this._findIcon(desktopEntry.Icon);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
@ -13,18 +24,9 @@ module.exports = React.createClass({
|
||||||
var label = desktopEntry.Name;
|
var label = desktopEntry.Name;
|
||||||
var category = desktopEntry.Categories;
|
var category = desktopEntry.Categories;
|
||||||
|
|
||||||
// Search for best icon
|
|
||||||
var icon = '';
|
|
||||||
|
|
||||||
if(!this.state.icon) {
|
|
||||||
this._findIcon(desktopEntry.Icon);
|
|
||||||
} else {
|
|
||||||
icon = this.state.icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className="desktop-app">
|
<li className="desktop-app">
|
||||||
<img src={icon} className="desktop-app-icon" />
|
<img src={this.state.icon} className="desktop-app-icon" />
|
||||||
<span className="desktop-app-label">{label}</span>
|
<span className="desktop-app-label">{label}</span>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
@ -33,12 +35,12 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
_findIcon: function(iconPath) {
|
_findIcon: function(iconPath) {
|
||||||
|
|
||||||
var desktopEntry = this.props.desktopEntry;
|
var self = this;
|
||||||
|
|
||||||
Util.DesktopApps.findIcon(iconPath)
|
Util.DesktopApps.findIcon(iconPath || 'application-default-icon')
|
||||||
.then(function(iconPath) {
|
.then(function(iconPath) {
|
||||||
this.setState({ icon: iconPath });
|
self.setState({ icon: iconPath });
|
||||||
}.bind(this))
|
})
|
||||||
;
|
;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var Util = require('../util');
|
var Util = require('../util');
|
||||||
var DesktopAppItem = require('./desktop-app-item.jsx');
|
var DesktopAppItem = require('./desktop-app-item.jsx');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
|
|
||||||
|
@ -12,6 +13,10 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
// Load system desktop apps
|
// Load system desktop apps
|
||||||
|
var baseDirs = global.process.env.XDG_DATA_DIRS.split(':').map(function(baseDir){
|
||||||
|
return path.join(baseDir, 'applications');
|
||||||
|
});
|
||||||
|
|
||||||
Util.DesktopApps.loadAllDesktopFiles('/usr/share/applications')
|
Util.DesktopApps.loadAllDesktopFiles('/usr/share/applications')
|
||||||
.then(function(desktopFiles) {
|
.then(function(desktopFiles) {
|
||||||
this.setState({ desktopFiles: desktopFiles });
|
this.setState({ desktopFiles: desktopFiles });
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
var React = require('react');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
isInViewport: function() {
|
||||||
|
|
||||||
|
var el = React.findDOMNode(this);
|
||||||
|
|
||||||
|
if(!el) return false;
|
||||||
|
|
||||||
|
var rect = el.getBoundingClientRect();
|
||||||
|
|
||||||
|
return (
|
||||||
|
rect.top >= 0 &&
|
||||||
|
rect.left >= 0 &&
|
||||||
|
rect.bottom <= (global.window.innerHeight || global.document.documentElement.clientHeight) && /*or $(window).height() */
|
||||||
|
rect.right <= (global.window.innerWidth || global.document.documentElement.clientWidth) /*or $(window).width() */
|
||||||
|
);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
|
||||||
|
function _onInViewport(){
|
||||||
|
if( this.isInViewport() ) {
|
||||||
|
this.onInViewport();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var el = React.findDOMNode(this);
|
||||||
|
|
||||||
|
if(typeof this.onInViewport === 'function') {
|
||||||
|
el.parentNode.addEventListener('scroll', debounce(_onInViewport.bind(this), 250));
|
||||||
|
}
|
||||||
|
|
||||||
|
_onInViewport.call(this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
function debounce(func, wait, immediate) {
|
||||||
|
var timeout;
|
||||||
|
return function() {
|
||||||
|
var context = this, args = arguments;
|
||||||
|
var later = function() {
|
||||||
|
timeout = null;
|
||||||
|
if (!immediate) func.apply(context, args);
|
||||||
|
};
|
||||||
|
var callNow = immediate && !timeout;
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(later, wait);
|
||||||
|
if (callNow) func.apply(context, args);
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,11 +1,17 @@
|
||||||
var ini = require('ini');
|
|
||||||
var glob = require('glob');
|
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var fs = require('fs');
|
var System = require('./system');
|
||||||
|
var debug = require('debug')('pitaya:desktop-apps');
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
var ICON_REALPATH_REGEX = /\..+$/;
|
var ICON_REALPATH_REGEX = /\..+$/;
|
||||||
|
var ICON_THEMES_ROOTDIR = '/usr/share/icons';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find and load all the desktop files in the subdirectories of given dirs
|
||||||
|
*
|
||||||
|
* @param Array[String] rootDirs
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
exports.loadAllDesktopFiles = function(rootDirs) {
|
exports.loadAllDesktopFiles = function(rootDirs) {
|
||||||
|
|
||||||
return exports.findAllDesktopFiles(rootDirs)
|
return exports.findAllDesktopFiles(rootDirs)
|
||||||
|
@ -28,23 +34,20 @@ exports.loadAllDesktopFiles = function(rootDirs) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.findAllDesktopFiles = function(rootDirs) {
|
/**
|
||||||
|
* Find all the desktop files in the subdirectories of given dirs
|
||||||
|
*
|
||||||
|
* @param Array[String] baseDirs
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
exports.findAllDesktopFiles = function(baseDirs) {
|
||||||
|
|
||||||
if(!Array.isArray(rootDirs)) {
|
if(!Array.isArray(baseDirs)) {
|
||||||
rootDirs = [rootDirs];
|
baseDirs = [baseDirs];
|
||||||
}
|
}
|
||||||
|
|
||||||
var promises = rootDirs.map(function(rootDir) {
|
var promises = baseDirs.map(function(baseDir) {
|
||||||
|
return System.findFiles('**/*.desktop', {cwd: baseDir, realpath: true});
|
||||||
var globPath = path.join(rootDir, '**/*.desktop');
|
|
||||||
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
glob(globPath, function(err, files) {
|
|
||||||
if(err) return reject(err);
|
|
||||||
return resolve(files);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
|
@ -55,30 +58,191 @@ exports.findAllDesktopFiles = function(rootDirs) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a .desktop file ans return its parsed content
|
||||||
|
*
|
||||||
|
* @param string filePath
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
exports.loadDesktopFile = function(filePath) {
|
exports.loadDesktopFile = function(filePath) {
|
||||||
return new Promise(function(resolve, reject) {
|
return System.loadINIFile(filePath);
|
||||||
fs.readFile(filePath, 'utf8', function(err, content) {
|
|
||||||
if(err) return reject(err);
|
|
||||||
try {
|
|
||||||
var decoded = ini.decode(content);
|
|
||||||
return resolve(decoded);
|
|
||||||
} catch(err) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.findIcon = function(iconPath) {
|
/**
|
||||||
return new Promise(function(resolve, reject) {
|
* Find the absolute path of a desktop icon
|
||||||
if( ICON_REALPATH_REGEX.test(iconPath) ) {
|
*
|
||||||
return resolve(iconPath);
|
* @param string iconPath
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
exports.findIcon = function(iconName, themeName, size, themeIgnore) {
|
||||||
|
|
||||||
|
themeIgnore = themeIgnore || [];
|
||||||
|
if(themeIgnore.indexOf(themeIgnore) !== -1) {
|
||||||
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
themeIgnore.push(themeName);
|
||||||
|
|
||||||
|
debug('Finding icon %s:%s:%s...', iconName, themeName, size);
|
||||||
|
|
||||||
|
if( ICON_REALPATH_REGEX.test(iconName) ) {
|
||||||
|
return Promise.resolve(iconName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!themeName) {
|
||||||
|
return exports.findIconThemes()
|
||||||
|
.then(function(themes) {
|
||||||
|
themeIgnore = themeIgnore || [];
|
||||||
|
var promises = themes.map(function(theme) {
|
||||||
|
return exports.findIcon(iconName, theme, size, themeIgnore);
|
||||||
});
|
});
|
||||||
|
return Promise.all(promises)
|
||||||
|
.then(exports._selectBestIcon)
|
||||||
|
;
|
||||||
|
})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exports.findClosestSizeIcon(iconName, themeName, size)
|
||||||
|
.then(function(foundIcon) {
|
||||||
|
|
||||||
|
if(foundIcon) return foundIcon;
|
||||||
|
|
||||||
|
debug('No icon found. Search in parents...');
|
||||||
|
|
||||||
|
return exports.findParentsThemeIcon(iconName, themeName, size, themeIgnore);
|
||||||
|
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.findParentsThemeIcon = function(iconName, themeName, size, themeIgnore) {
|
||||||
|
|
||||||
|
return exports.themeIndexExists(themeName)
|
||||||
|
.then(function(exists) {
|
||||||
|
|
||||||
|
if(!exists) return null;
|
||||||
|
|
||||||
|
return exports.loadThemeIndex(themeName)
|
||||||
|
.then(function(themeIndex) {
|
||||||
|
|
||||||
|
if(!themeIndex || !themeIndex['Icon Theme'].Inherits) return;
|
||||||
|
|
||||||
|
var parents = themeIndex['Icon Theme'].Inherits.split(',');
|
||||||
|
|
||||||
|
debug('Found parents %j', parents);
|
||||||
|
|
||||||
|
var promises = parents.map(function(themeName) {
|
||||||
|
return exports.findIcon(iconName, themeName, size, themeIgnore);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises)
|
||||||
|
.then(exports._selectBestIcon)
|
||||||
|
;
|
||||||
|
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.findClosestSizeIcon = function(iconName, themeName, size) {
|
||||||
|
|
||||||
|
var themePath = path.join(ICON_THEMES_ROOTDIR, themeName);
|
||||||
|
|
||||||
|
var extPattern = '{svg,png}';
|
||||||
|
var filePattern = themeName+'/*/*/'+iconName+'.'+extPattern;
|
||||||
|
|
||||||
|
debug('File pattern %s', filePattern);
|
||||||
|
|
||||||
|
return System.findFiles(filePattern, {cwd: ICON_THEMES_ROOTDIR})
|
||||||
|
.then(function(iconFiles) {
|
||||||
|
|
||||||
|
debug('Found files %j', iconFiles);
|
||||||
|
|
||||||
|
var scalableIcon = iconFiles.reduce(function(scalableIcon, iconPath) {
|
||||||
|
if(iconPath.indexOf('scalable') !== -1) {
|
||||||
|
debug('Found scalable icon %s', iconPath);
|
||||||
|
scalableIcon = iconPath;
|
||||||
|
}
|
||||||
|
return scalableIcon;
|
||||||
|
}, null);
|
||||||
|
|
||||||
|
if(scalableIcon) return scalableIcon;
|
||||||
|
|
||||||
|
if(!size) {
|
||||||
|
size = Math.max.apply(Math, clean(iconFiles.map(sizeFromPath)));
|
||||||
|
}
|
||||||
|
|
||||||
|
var closestIcon = iconFiles.reduce(function(foundIcon, iconPath) {
|
||||||
|
var foundSize = sizeFromPath(iconPath);
|
||||||
|
if( foundSize && Math.abs(foundSize - size) < Math.abs(foundIcon.size - size) ) {
|
||||||
|
foundIcon.path = iconPath;
|
||||||
|
foundIcon.size = foundSize;
|
||||||
|
}
|
||||||
|
return foundIcon;
|
||||||
|
}, {path: null, size: null});
|
||||||
|
|
||||||
|
return closestIcon.path;
|
||||||
|
|
||||||
|
})
|
||||||
|
.then(function(iconPath) {
|
||||||
|
debug('Closest icon %j', iconPath);
|
||||||
|
return iconPath ? path.join(ICON_THEMES_ROOTDIR, iconPath) : null;
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
function sizeFromPath(iconPath) {
|
||||||
|
var simpleSizeRegex = /\/(\d+)\//;
|
||||||
|
var matches = simpleSizeRegex.exec(iconPath);
|
||||||
|
if(matches && matches[1]) return +matches[1];
|
||||||
|
var doubleSizeRegex = /\/(\d+)x\d+\//;
|
||||||
|
matches = doubleSizeRegex.exec(iconPath);
|
||||||
|
if(matches && matches[1]) return +matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
exports._selectBestIcon = function(iconPaths) {
|
||||||
|
var iconSelection = iconPaths.reduce(function(iconSelection, iconPath) {
|
||||||
|
if(iconPath) {
|
||||||
|
var key = iconPath.indexOf('scalable') !== -1 ? 'scalable' : 'bitmap';
|
||||||
|
iconSelection[key] = iconPath;
|
||||||
|
}
|
||||||
|
return iconSelection;
|
||||||
|
}, {scalable: null, bitmap: null});
|
||||||
|
debug('Icon selection %j', iconSelection);
|
||||||
|
return iconSelection.scalable || iconSelection.bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.findIconThemes = function() {
|
||||||
|
return System.findFiles('*/', {cwd: ICON_THEMES_ROOTDIR, realpath: true})
|
||||||
|
.then(function(files) {
|
||||||
|
return files.map(path.basename.bind(path));
|
||||||
|
})
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.loadThemeIndex = function(themeName) {
|
||||||
|
var themeIndexPath = path.join(ICON_THEMES_ROOTDIR, themeName, 'index.theme');
|
||||||
|
return System.loadINIFile(themeIndexPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.themeIndexExists = function(themeName) {
|
||||||
|
var themeIndexPath = path.join(ICON_THEMES_ROOTDIR, themeName, 'index.theme');
|
||||||
|
return System.exists(themeIndexPath);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Array helpers
|
// Array helpers
|
||||||
|
|
||||||
|
function clean(arr) {
|
||||||
|
return arr.filter(function(item) {
|
||||||
|
return item !== null && item !== undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function flatten(arr) {
|
function flatten(arr) {
|
||||||
return arr.reduce(function(result, item) {
|
return arr.reduce(function(result, item) {
|
||||||
result = result.concat.apply(result, Array.isArray(item) ? flatten(item) : [item]);
|
result = result.concat.apply(result, Array.isArray(item) ? flatten(item) : [item]);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var cp = require('child_process');
|
var cp = require('child_process');
|
||||||
|
var glob = require('glob');
|
||||||
|
var ini = require('ini');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a JSON file
|
* Load a JSON file
|
||||||
|
@ -21,6 +23,26 @@ exports.loadJSONFile = function(filePath) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a INI file
|
||||||
|
*
|
||||||
|
* @param filePath The path of the json file
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
exports.loadINIFile = function(filePath) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
fs.readFile(filePath, 'utf8', function(err, content) {
|
||||||
|
if(err) return reject(err);
|
||||||
|
try {
|
||||||
|
var decoded = ini.decode(content);
|
||||||
|
return resolve(decoded);
|
||||||
|
} catch(err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
exports.runApp = function(execPath) {
|
exports.runApp = function(execPath) {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
cp.exec(execPath, function(err) {
|
cp.exec(execPath, function(err) {
|
||||||
|
@ -29,3 +51,34 @@ exports.runApp = function(execPath) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var _globCache = {
|
||||||
|
statCache: {},
|
||||||
|
cache: {},
|
||||||
|
realpathCache: {},
|
||||||
|
symlinks: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.findFiles = function(pattern, opts) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
|
||||||
|
opts = opts || {};
|
||||||
|
opts.cache = _globCache.cache;
|
||||||
|
opts.statCache = _globCache.statCache;
|
||||||
|
opts.realpathCache = _globCache.realpathCache;
|
||||||
|
opts.symlinks = _globCache.symlinks;
|
||||||
|
|
||||||
|
glob(pattern, opts, function(err, files) {
|
||||||
|
if(err) return reject(err);
|
||||||
|
return resolve(files);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.exists = function(filePath) {
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
fs.exists(filePath, resolve);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -9,9 +9,11 @@
|
||||||
"grunt-contrib-clean": "^0.6.0",
|
"grunt-contrib-clean": "^0.6.0",
|
||||||
"grunt-contrib-copy": "^0.7.0",
|
"grunt-contrib-copy": "^0.7.0",
|
||||||
"grunt-nw": "git+https://github.com/snap-project/grunt-nw#develop",
|
"grunt-nw": "git+https://github.com/snap-project/grunt-nw#develop",
|
||||||
"lodash": "^3.0.1"
|
"lodash": "^3.0.1",
|
||||||
|
"nodeunit": "^0.9.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"test": "./node_modules/.bin/nodeunit test",
|
||||||
"start": "./node_modules/.bin/grunt pitaya:run",
|
"start": "./node_modules/.bin/grunt pitaya:run",
|
||||||
"build": "./node_modules/.bin/grunt pitaya:build"
|
"build": "./node_modules/.bin/grunt pitaya:build"
|
||||||
},
|
},
|
||||||
|
@ -21,6 +23,7 @@
|
||||||
"kiosk": false
|
"kiosk": false
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"debug": "^2.2.0",
|
||||||
"glob": "^5.0.14",
|
"glob": "^5.0.14",
|
||||||
"ini": "^1.3.4",
|
"ini": "^1.3.4",
|
||||||
"minimist": "^1.1.3",
|
"minimist": "^1.1.3",
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
var DesktopApps = require('../js/util/desktop-apps');
|
||||||
|
|
||||||
|
var DesktopSuite = exports.DesktopSuite = {};
|
||||||
|
|
||||||
|
|
||||||
|
DesktopSuite.findIconThemes = function(test) {
|
||||||
|
|
||||||
|
DesktopApps.findIconThemes()
|
||||||
|
.then(function(themes) {
|
||||||
|
//console.log(themes);
|
||||||
|
test.ok(themes.length > 0);
|
||||||
|
test.done();
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
test.ifError(err);
|
||||||
|
test.done();
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
DesktopSuite.findIcon = function(test) {
|
||||||
|
|
||||||
|
DesktopApps.findIcon('nm-device-wireless')
|
||||||
|
.then(function(iconPath) {
|
||||||
|
//console.log('findIcon', iconPath);
|
||||||
|
test.done();
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
test.ifError(err);
|
||||||
|
test.done();
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
};
|
Loading…
Reference in New Issue