Javascript mimetype icon resolver

This makes it possible to retrieve the icon for mimetypes in javascript.
It makes no additional queries to the server to retrieve the mimetype.

* config/mimetypealiases.json added
* mimetype.js: this is where the logic resides to convert from mimetype
  to icon url
* mimetypelist.js: generated file with a list of mimetype mapping (aliases)
  and the list of icon files
* ./occ maintenance:mimetypesjs : new command for occ to gernerate
  mimetypes.js
* unit tests updated and still work
* javascript tests added
* theming support
* folder of the theme is now present in javascript (OC.theme.folder)
This commit is contained in:
Roeland Jago Douma 2015-06-03 14:52:00 +02:00
parent 14eef434ff
commit c8145cdbd6
9 changed files with 559 additions and 2 deletions

View File

@ -0,0 +1,68 @@
{
"_comment" : "When this file is changed make sure to run",
"_comment2": "./occ maintenance:mimetypesjs",
"_comment3": "Otherwise your update won't propagate through the system",
"application/coreldraw": "image",
"application/font-sfnt": "font",
"application/font-woff": "font",
"application/illustrator": "image/vector",
"application/json": "text/code",
"application/msaccess": "database",
"application/msexcel": "x-office/spreadsheet",
"application/mspowerpoint": "x-office/presentation",
"application/msword": "x-office/document",
"application/octet-stream": "file",
"application/postscript": "image/vector",
"application/vnd.android.package-archive": "package/x-generic",
"application/vnd.ms-excel": "x-office/spreadsheet",
"application/vnd.ms-excel.addin.macroEnabled.12": "x-office/spreadsheet",
"application/vnd.ms-excel.sheet.binary.macroEnabled.12": "x-office/spreadsheet",
"application/vnd.ms-excel.sheet.macroEnabled.12": "x-office/spreadsheet",
"application/vnd.ms-excel.template.macroEnabled.12": "x-office/spreadsheet",
"application/vnd.ms-fontobject": "font",
"application/vnd.ms-powerpoint": "x-office/presentation",
"application/vnd.ms-powerpoint.addin.macroEnabled.12": "x-office/presentation",
"application/vnd.ms-powerpoint.presentation.macroEnabled.12": "x-office/presentation",
"application/vnd.ms-powerpoint.slideshow.macroEnabled.12": "x-office/presentation",
"application/vnd.ms-powerpoint.template.macroEnabled.12": "x-office/presentation",
"application/vnd.ms-word.document.macroEnabled.12": "x-office/document",
"application/vnd.ms-word.template.macroEnabled.12": "x-office/document",
"application/vnd.oasis.opendocument.presentation": "x-office/presentation",
"application/vnd.oasis.opendocument.presentation-template": "x-office/presentation",
"application/vnd.oasis.opendocument.spreadsheet": "x-office/spreadsheet",
"application/vnd.oasis.opendocument.spreadsheet-template": "x-office/spreadsheet",
"application/vnd.oasis.opendocument.text": "x-office/document",
"application/vnd.oasis.opendocument.text-master": "x-office/document",
"application/vnd.oasis.opendocument.text-template": "x-office/document",
"application/vnd.oasis.opendocument.text-web": "x-office/document",
"application/vnd.openxmlformats-officedocument.presentationml.presentation": "x-office/presentation",
"application/vnd.openxmlformats-officedocument.presentationml.slideshow": "x-office/presentation",
"application/vnd.openxmlformats-officedocument.presentationml.template": "x-office/presentation",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "x-office/spreadsheet",
"application/vnd.openxmlformats-officedocument.spreadsheetml.template": "x-office/spreadsheet",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "x-office/document",
"application/vnd.openxmlformats-officedocument.wordprocessingml.template": "x-office/document",
"application/x-7z-compressed": "package/x-generic",
"application/x-compressed": "package/x-generic",
"application/x-dcraw": "image",
"application/x-deb": "package/x-generic",
"application/x-font": "font",
"application/x-gimp": "image",
"application/x-gzip": "package/x-generic",
"application/x-perl": "text/code",
"application/x-photoshop": "image",
"application/x-php": "text/code",
"application/x-rar-compressed": "package/x-generic",
"application/x-tar": "package/x-generic",
"application/x-tex": "text",
"application/xml": "text/html",
"application/yaml": "text/code",
"application/zip": "package/x-generic",
"image/svg+xml": "image/vector",
"text/css": "text/code",
"text/csv": "x-office/spreadsheet",
"text/x-shellscript": "text/code"
}

View File

@ -0,0 +1,112 @@
<?php
/**
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OC\Core\Command\Maintenance;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class MimeTypesJS extends Command {
protected function configure() {
$this
->setName('maintenance:mimetypesjs')
->setDescription('Update mimetypelist.js');
}
protected function execute(InputInterface $input, OutputInterface $output) {
// Fetch all the aliases
$aliases = json_decode(file_get_contents(dirname(__DIR__) . '/../../config/mimetypealiases.json'), true);
// Remove comments
$keys = array_filter(array_keys($aliases), function($k) {
return $k[0] === '_';
});
foreach($keys as $key) {
unset($aliases[$key]);
}
// Fetch all files
$dir = new \DirectoryIterator(dirname(__DIR__) . '/../img/filetypes');
$files = [];
foreach($dir as $fileInfo) {
if ($fileInfo->isFile()) {
$file = preg_replace('/.[^.]*$/', '', $fileInfo->getFilename());
$files[] = $file;
}
}
//Remove duplicates
$files = array_values(array_unique($files));
// Fetch all themes!
$themes = [];
$dirs = new \DirectoryIterator(dirname(__DIR__) . '/../../themes/');
foreach($dirs as $dir) {
//Valid theme dir
if ($dir->isFile() || $dir->isDot()) {
continue;
}
$theme = $dir->getFilename();
$themeDir = $dir->getPath() . '/' . $theme . '/core/img/filetypes/';
// Check if this theme has its own filetype icons
if (!file_exists($themeDir)) {
continue;
}
$themes[$theme] = [];
// Fetch all the theme icons!
$themeIt = new \DirectoryIterator($themeDir);
foreach ($themeIt as $fileInfo) {
if ($fileInfo->isFile()) {
$file = preg_replace('/.[^.]*$/', '', $fileInfo->getFilename());
$themes[$theme][] = $file;
}
}
//Remove Duplicates
$themes[$theme] = array_values(array_unique($themes[$theme]));
}
//Generate the JS
$js = '/**
* This file is automatically generated
* DO NOT EDIT MANUALLY!
*
* You can update the list of MimeType Aliases in config/mimetypealiases.json
* The list of files is fetched from core/img/filetypes
* To regenerate this file run ./occ maintenance:mimetypesjs
*/
OC.MimeTypeList={
aliases: ' . json_encode($aliases, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . ',
files: ' . json_encode($files, JSON_PRETTY_PRINT) . ',
themes: ' . json_encode($themes, JSON_PRETTY_PRINT) . '
};
';
//Output the JS
file_put_contents(dirname(__DIR__) . '/../js/mimetypelist.js', $js);
$output->writeln('<info>mimetypelist.js is updated');
}
}

View File

@ -128,7 +128,8 @@ $array = array(
'slogan' => $defaults->getSlogan(),
'logoClaim' => $defaults->getLogoClaim(),
'shortFooter' => $defaults->getShortFooter(),
'longFooter' => $defaults->getLongFooter()
'longFooter' => $defaults->getLongFooter(),
'folder' => OC_Util::getTheme(),
)
)
);

View File

@ -27,6 +27,8 @@
"multiselect.js",
"oc-requesttoken.js",
"setupchecks.js",
"../search/js/search.js"
"../search/js/search.js",
"mimetype.js",
"mimetypelist.js"
]
}

113
core/js/mimetype.js Normal file
View File

@ -0,0 +1,113 @@
/**
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
/**
* Namespace to hold functions related to convert mimetype to icons
*
* @namespace
*/
OC.MimeType = {
/**
* Cache that maps mimeTypes to icon urls
*/
_mimeTypeIcons: {},
/**
* Return the file icon we want to use for the given mimeType.
* The file needs to be present in the supplied file list
*
* @param {string} mimeType The mimeType we want an icon for
* @param {array} files The available icons in this theme
* @return {string} The icon to use or null if there is no match
*/
_getFile: function(mimeType, files) {
var icon = mimeType.replace(new RegExp('/', 'g'), '-');
// Generate path
if (mimeType === 'dir' && $.inArray('folder', files) !== -1) {
return 'folder';
} else if (mimeType === 'dir-shared' && $.inArray('folder-shared', files) !== -1) {
return 'folder-shared';
} else if (mimeType === 'dir-external' && $.inArray('folder-external', files) !== -1) {
return 'folder-external';
} else if ($.inArray(icon, files) !== -1) {
return icon;
} else if ($.inArray(icon.split('-')[0], files) !== -1) {
return icon.split('-')[0];
} else if ($.inArray('file', files) !== -1) {
return 'file';
}
return null;
},
/**
* Return the url to icon of the given mimeType
*
* @param {string} mimeType The mimeType to get the icon for
* @return {string} Url to the icon for mimeType
*/
getIconUrl: function(mimeType) {
if (_.isUndefined(mimeType)) {
return undefined;
}
if (mimeType in OC.MimeTypeList.aliases) {
mimeType = OC.MimeTypeList.aliases[mimeType];
}
if (mimeType in OC.MimeType._mimeTypeIcons) {
return OC.MimeType._mimeTypeIcons[mimeType];
}
// First try to get the correct icon from the current theme
var gotIcon = null;
var path = '';
if (OC.theme.folder !== '' && $.isArray(OC.MimeTypeList.themes[OC.theme.folder])) {
path = OC.webroot + '/themes/' + OC.theme.folder + '/core/img/filetypes/';
var icon = OC.MimeType._getFile(mimeType, OC.MimeTypeList.themes[OC.theme.folder]);
if (icon !== null) {
gotIcon = true;
path += icon;
}
}
// If we do not yet have an icon fall back to the default
if (gotIcon === null) {
path = OC.webroot + '/core/img/filetypes/';
path += OC.MimeType._getFile(mimeType, OC.MimeTypeList.files);
}
// Use svg if we can
if(OC.Util.hasSVGSupport()){
path += '.svg';
} else {
path += '.png';
}
// Cache the result
OC.MimeType._mimeTypeIcons[mimeType] = path;
return path;
}
};

107
core/js/mimetypelist.js Normal file
View File

@ -0,0 +1,107 @@
/**
* This file is automatically generated
* DO NOT EDIT MANUALLY!
*
* You can update the list of MimeType Aliases in config/mimetypealiases.json
* The list of files is fetched from core/img/filetypes
* To regenerate this file run ./occ maintenance:mimetypesjs
*/
OC.MimeTypeList={
aliases: {
"application/coreldraw": "image",
"application/font-sfnt": "font",
"application/font-woff": "font",
"application/illustrator": "image/vector",
"application/json": "text/code",
"application/msaccess": "database",
"application/msexcel": "x-office/spreadsheet",
"application/mspowerpoint": "x-office/presentation",
"application/msword": "x-office/document",
"application/octet-stream": "file",
"application/postscript": "image/vector",
"application/vnd.android.package-archive": "package/x-generic",
"application/vnd.ms-excel": "x-office/spreadsheet",
"application/vnd.ms-excel.addin.macroEnabled.12": "x-office/spreadsheet",
"application/vnd.ms-excel.sheet.binary.macroEnabled.12": "x-office/spreadsheet",
"application/vnd.ms-excel.sheet.macroEnabled.12": "x-office/spreadsheet",
"application/vnd.ms-excel.template.macroEnabled.12": "x-office/spreadsheet",
"application/vnd.ms-fontobject": "font",
"application/vnd.ms-powerpoint": "x-office/presentation",
"application/vnd.ms-powerpoint.addin.macroEnabled.12": "x-office/presentation",
"application/vnd.ms-powerpoint.presentation.macroEnabled.12": "x-office/presentation",
"application/vnd.ms-powerpoint.slideshow.macroEnabled.12": "x-office/presentation",
"application/vnd.ms-powerpoint.template.macroEnabled.12": "x-office/presentation",
"application/vnd.ms-word.document.macroEnabled.12": "x-office/document",
"application/vnd.ms-word.template.macroEnabled.12": "x-office/document",
"application/vnd.oasis.opendocument.presentation": "x-office/presentation",
"application/vnd.oasis.opendocument.presentation-template": "x-office/presentation",
"application/vnd.oasis.opendocument.spreadsheet": "x-office/spreadsheet",
"application/vnd.oasis.opendocument.spreadsheet-template": "x-office/spreadsheet",
"application/vnd.oasis.opendocument.text": "x-office/document",
"application/vnd.oasis.opendocument.text-master": "x-office/document",
"application/vnd.oasis.opendocument.text-template": "x-office/document",
"application/vnd.oasis.opendocument.text-web": "x-office/document",
"application/vnd.openxmlformats-officedocument.presentationml.presentation": "x-office/presentation",
"application/vnd.openxmlformats-officedocument.presentationml.slideshow": "x-office/presentation",
"application/vnd.openxmlformats-officedocument.presentationml.template": "x-office/presentation",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "x-office/spreadsheet",
"application/vnd.openxmlformats-officedocument.spreadsheetml.template": "x-office/spreadsheet",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "x-office/document",
"application/vnd.openxmlformats-officedocument.wordprocessingml.template": "x-office/document",
"application/x-7z-compressed": "package/x-generic",
"application/x-compressed": "package/x-generic",
"application/x-dcraw": "image",
"application/x-deb": "package/x-generic",
"application/x-font": "font",
"application/x-gimp": "image",
"application/x-gzip": "package/x-generic",
"application/x-perl": "text/code",
"application/x-photoshop": "image",
"application/x-php": "text/code",
"application/x-rar-compressed": "package/x-generic",
"application/x-tar": "package/x-generic",
"application/x-tex": "text",
"application/xml": "text/html",
"application/yaml": "text/code",
"application/zip": "package/x-generic",
"image/svg+xml": "image/vector",
"text/css": "text/code",
"text/csv": "x-office/spreadsheet",
"text/x-shellscript": "text/code"
},
files: [
"text-x-h",
"application-rss+xml",
"video",
"folder-drag-accept",
"application-epub+zip",
"folder-public",
"package-x-generic",
"application-x-shockwave-flash",
"text",
"folder-external",
"web",
"text-vcard",
"application",
"image-vector",
"database",
"text-code",
"text-x-python",
"x-office-spreadsheet",
"application-pdf",
"folder",
"x-office-document",
"text-html",
"text-calendar",
"x-office-presentation",
"text-x-c",
"file",
"font",
"folder-shared",
"application-x-cbr",
"application-javascript",
"image",
"audio"
],
themes: []
};

View File

@ -0,0 +1,151 @@
/**
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
describe('MimeType tests', function() {
var _files;
var _aliases;
var _theme;
beforeEach(function() {
_files = OC.MimeTypeList.files;
_aliases = OC.MimeTypeList.aliases;
_theme = OC.MimeTypeList.themes['abc'];
OC.MimeTypeList.files = ['folder', 'folder-shared', 'folder-external', 'foo-bar', 'foo', 'file'];
OC.MimeTypeList.aliases = {'app/foobar': 'foo/bar'};
OC.MimeTypeList.themes['abc'] = ['folder'];
});
afterEach(function() {
OC.MimeTypeList.files = _files;
OC.MimeTypeList.aliases = _aliases;
OC.MimeTypeList.themes['abc'] = _theme;
});
describe('_getFile', function() {
it('returns the correct icon for "dir"', function() {
var res = OC.MimeType._getFile('dir', OC.MimeTypeList.files);
expect(res).toEqual('folder');
});
it('returns the correct icon for "dir-shared"', function() {
var res = OC.MimeType._getFile('dir-shared', OC.MimeTypeList.files);
expect(res).toEqual('folder-shared');
});
it('returns the correct icon for "dir-external"', function() {
var res = OC.MimeType._getFile('dir-external', OC.MimeTypeList.files);
expect(res).toEqual('folder-external');
});
it('returns the correct icon for a mimetype for which we have an icon', function() {
var res = OC.MimeType._getFile('foo/bar', OC.MimeTypeList.files);
expect(res).toEqual('foo-bar');
});
it('returns the correct icon for a mimetype for which we only have a general mimetype icon', function() {
var res = OC.MimeType._getFile('foo/baz', OC.MimeTypeList.files);
expect(res).toEqual('foo');
});
it('return the file mimetype if we have no matching icon but do have a file icon', function() {
var res = OC.MimeType._getFile('foobar', OC.MimeTypeList.files);
expect(res).toEqual('file');
});
it('return null if we do not have a matching icon', function() {
var res = OC.MimeType._getFile('xyz', []);
expect(res).toEqual(null);
});
});
describe('getIconUrl', function() {
describe('no theme', function() {
var _themeFolder;
beforeEach(function() {
_themeFolder = OC.theme.folder;
OC.theme.folder = '';
//Clear mimetypeIcons caches
OC.MimeType._mimeTypeIcons = {};
});
afterEach(function() {
OC.theme.folder = _themeFolder;
});
it('return undefined if the an icon for undefined is requested', function() {
var res = OC.MimeType.getIconUrl(undefined);
expect(res).toEqual(undefined);
});
it('return the url for the mimetype file', function() {
var res = OC.MimeType.getIconUrl('file');
expect(res).toEqual(OC.webroot + '/core/img/filetypes/file.svg');
});
it('test if the cache works correctly', function() {
OC.MimeType._mimeTypeIcons = {};
expect(Object.keys(OC.MimeType._mimeTypeIcons).length).toEqual(0);
var res = OC.MimeType.getIconUrl('dir');
expect(Object.keys(OC.MimeType._mimeTypeIcons).length).toEqual(1);
expect(OC.MimeType._mimeTypeIcons['dir']).toEqual(res);
var res = OC.MimeType.getIconUrl('dir-shared');
expect(Object.keys(OC.MimeType._mimeTypeIcons).length).toEqual(2);
expect(OC.MimeType._mimeTypeIcons['dir-shared']).toEqual(res);
});
it('test if alaiases are converted correctly', function() {
var res = OC.MimeType.getIconUrl('app/foobar');
expect(res).toEqual(OC.webroot + '/core/img/filetypes/foo-bar.svg');
expect(OC.MimeType._mimeTypeIcons['foo/bar']).toEqual(res);
});
});
describe('themes', function() {
var _themeFolder;
beforeEach(function() {
_themeFolder = OC.theme.folder;
OC.theme.folder = 'abc';
//Clear mimetypeIcons caches
OC.MimeType._mimeTypeIcons = {};
});
afterEach(function() {
OC.theme.folder = _themeFolder;
});
it('test if theme path is used if a theme icon is availble', function() {
var res = OC.MimeType.getIconUrl('dir');
expect(res).toEqual(OC.webroot + '/themes/abc/core/img/filetypes/folder.svg');
});
it('test if we fallback to the default theme if no icon is available in the theme', function() {
var res = OC.MimeType.getIconUrl('dir-shared');
expect(res).toEqual(OC.webroot + '/core/img/filetypes/folder-shared.svg');
});
});
});
});

View File

@ -56,6 +56,7 @@ if (\OC::$server->getConfig()->getSystemValue('installed', false)) {
$application->add(new OC\Core\Command\Encryption\ListModules(\OC::$server->getEncryptionManager()));
$application->add(new OC\Core\Command\Encryption\SetDefaultModule(\OC::$server->getEncryptionManager()));
$application->add(new OC\Core\Command\Encryption\Status(\OC::$server->getEncryptionManager()));
$application->add(new OC\Core\Command\Maintenance\MimeTypesJS());
} else {
$application->add(new OC\Core\Command\Maintenance\Install(\OC::$server->getConfig()));
}

View File

@ -406,6 +406,8 @@ class OC {
OC_Util::addScript('search', 'search');
OC_Util::addScript("oc-requesttoken");
OC_Util::addScript("apps");
OC_Util::addScript('mimetype');
OC_Util::addScript('mimetypelist');
OC_Util::addVendorScript('snapjs/dist/latest/snap');
// avatars