Merge branch 'javascript-refactor' into dev

This commit is contained in:
Oliver Hamlet
2016-01-06 18:56:14 +00:00
35 changed files with 4098 additions and 2364 deletions
+23
View File
@@ -0,0 +1,23 @@
env:
es6: true
mocha: true
amd: true
node: true
browser: true
ecmaFeatures:
modules: false
globals:
loot: false
should: false
extends:
- "eslint:recommended"
- "airbnb/base"
rules:
strict:
- 2
- global
guard-for-in: 0
+19 -1
View File
@@ -20,6 +20,7 @@ addons:
- libssl-dev
- gcc-5
- g++-5
sauce_connect: true
install:
# Use GCC 5.
@@ -27,6 +28,16 @@ install:
# Run install step script to download and build dependencies.
- chmod +x scripts/install-step.travis.sh
- ./scripts/install-step.travis.sh
# Install the latest stable Node.js. The default Node.js version is too old
# for some of the JavaScript syntax used.
- npm install -g nvm
- nvm install node
# Install Node.js dependencies
- npm install
# Add local binary path to PATH
- export PATH="./node_modules/.bin:$PATH"
# Install runtime dependencies using Bower
- bower install
before_script:
# Build Google Test
@@ -46,7 +57,9 @@ before_script:
# Travis machines are 64 bit, and the dependencies use dynamic linking.
- cmake .. -DPROJECT_ARCH=64 -DPROJECT_STATIC_RUNTIME=OFF -DBUILD_SHARED_LIBS=OFF -DGTEST_ROOT=../../googletest-release-1.7.0
script: make tests && ./tests
script:
- npm test
- make tests && ./tests
before_deploy:
# Build the metadata validator
@@ -69,3 +82,8 @@ notifications:
- "chat.freenode.net#loot"
use_notice: true
skip_join: true
env:
global:
- secure: OWgDkff/b+0eKk/P75rBnecaPDv1E/gMkCzsTUUtofmzj+sttpMUsh8VOVUvckGs5m3fRwRhc/t99gR4FuDtMOVE5JZ8CqZn7tcv2wNAspQ613pS0nWyIX/IUbyF+gjtPW2dWy81hKVtTP4yFvUn1Gk+JRjJLSyxM53Xt6oTOlY=
- secure: XpGbqizjWfaGiWDkrcW4UhSW8ijm00jgSo2qkthza3QmHQ3C0Vye3gQjjITCq+y6izQTPa46fxaI+Ozligyh4aQ1G8SpCa77tXMBfvo31led+s81FlAOSVGDJ/2eDOoawFuj5dTKTPR1zLniDYH8AqG8EDZuLoK6fhx7CchU2Yw=
+17
View File
@@ -37,5 +37,22 @@
"jed-gettext-parser": "~1.0.0",
"paper-toggle-button": "Polymer/paper-toggle-button#~0.5.4",
"core-overlay": "WrinklyNinja/core-overlay#fix-focus-self-as-next"
},
"resolutions": {
"polymer": "^0.5",
"core-icons": "^0.5",
"core-icon": "^0.5",
"core-collapse": "^0.5",
"core-focusable": "^0.5",
"core-icon-button": "^0.5",
"core-resizable": "^0.5",
"core-iconset-svg": "^0.5",
"core-dropdown": "null-dimensions-positions-fix",
"core-transition": "^0.5",
"core-overlay": "fix-focus-self-as-next",
"webcomponentsjs": "^0.7.18",
"core-iconset": "^0.5",
"core-selection": "^0.5",
"core-meta": "^0.5"
}
}
+39
View File
@@ -0,0 +1,39 @@
'use strict';
module.exports = (grunt) => {
grunt.initConfig({
connect: {
server: {
options: {
base: '',
port: 9999,
},
},
},
'saucelabs-mocha': {
all: {
options: {
urls: ['http://127.0.0.1:9999/src/tests/gui/html/js/test.html'],
build: process.env.TRAVIS_JOB_ID,
throttled: 3,
browsers: [{
browserName: 'chrome',
platform: 'Windows 10',
version: '47',
}],
testname: 'LOOT UI JS Tests',
},
},
},
watch: {},
});
// Loading dependencies
for (const key in grunt.file.readJSON('package.json').devDependencies) {
if (key !== 'grunt' && key.indexOf('grunt') === 0) {
grunt.loadNpmTasks(key);
}
}
grunt.registerTask('dev', ['connect', 'watch']);
grunt.registerTask('test', ['connect', 'saucelabs-mocha']);
};
+12
View File
@@ -14,7 +14,19 @@
"private": true,
"devDependencies": {
"bower": "^1.7.1",
"eslint": "^1.10.3",
"eslint-config-airbnb": "^2.0.0",
"fs-extra": "^0.26.2",
"grunt": "^0.4.5",
"grunt-cli": "^0.1.13",
"grunt-contrib-connect": "^0.11.2",
"grunt-contrib-watch": "^0.6.1",
"grunt-saucelabs": "^8.6.2",
"mocha": "^2.3.4",
"should": "^8.0.1",
"vulcanize": "^0.7.11"
},
"scripts": {
"test": "grunt test"
}
}
+177 -180
View File
@@ -2,206 +2,203 @@
// Archive packaging script. Takes one argument, which is the path to the
// repository's root. Requires 7-zip and Git to be installed, and Git to be
// available on the system path.
'use strict';
const childProcess = require('child_process');
const path = require('path');
const fs = require('fs-extra');
const os = require('os');
const helpers = require('./helpers');
var child_process = require('child_process');
var path = require('path');
var fs = require('fs-extra');
var os = require('os');
var helpers = require('./helpers');
function vulcanize() {
return child_process.execFileSync('node', [
'scripts/vulcanize.js',
root_path
]);
function vulcanize(rootPath) {
return childProcess.execFileSync('node', [
'scripts/vulcanize.js',
rootPath,
]);
}
function getGitDescription() {
return String(child_process.execFileSync('git', [
'describe',
'--tags',
'--long'
])).slice(0, -1);
return String(childProcess.execFileSync('git', [
'describe',
'--tags',
'--long',
])).slice(0, -1);
}
function compress(source_path, dest_path) {
var sevenzip_path = '';
if (os.platform() == 'win32') {
sevenzip_path = path.join('C:\\', 'Program Files', '7-Zip', '7z.exe');
} else {
sevenzip_path = '/usr/bin/7z';
function compress(sourcePath, destPath) {
let sevenzipPath = '';
if (os.platform() === 'win32') {
sevenzipPath = path.join('C:\\', 'Program Files', '7-Zip', '7z.exe');
} else {
sevenzipPath = '/usr/bin/7z';
}
// First remove any existing archive.
fs.removeSync(destPath);
// The last argument must have a leading dot for the subdirectory not to
// be present in the archive, but path.join removes it, so it's prefixed.
return childProcess.execFileSync(sevenzipPath, [
'a',
'-r',
destPath,
'.' + path.sep + path.join(sourcePath, '*'),
]);
}
function createAppArchive(rootPath, releasePath, tempPath, destPath) {
// Ensure that the output directory is empty.
fs.emptyDirSync(tempPath);
// Copy LOOT exectuable and CEF files.
let binaries = [];
if (os.platform() === 'win32') {
binaries = [
'LOOT.exe',
'd3dcompiler_47.dll',
'libEGL.dll',
'libGLESv2.dll',
'libcef.dll',
'natives_blob.bin',
'snapshot_blob.bin',
'cef.pak',
'cef_100_percent.pak',
'cef_200_percent.pak',
'devtools_resources.pak',
'icudtl.dat',
];
if (helpers.fileExists(path.join(releasePath, 'wow_helper.exe'))) {
binaries.push('wow_helper.exe');
}
} else {
binaries = [
'LOOT',
'chrome-sandbox',
'libcef.so',
'natives_blob.bin',
'snapshot_blob.bin',
'cef.pak',
'cef_100_percent.pak',
'cef_200_percent.pak',
'devtools_resources.pak',
'icudtl.dat',
];
}
binaries.forEach((file) => {
fs.copySync(
path.join(releasePath, file),
path.join(tempPath, file)
);
});
// First remove any existing archive.
fs.removeSync(dest_path);
// CEF locale file.
fs.mkdirsSync(path.join(tempPath, 'resources', 'l10n'));
fs.copySync(
path.join(releasePath, 'resources', 'l10n', 'en-US.pak'),
path.join(tempPath, 'resources', 'l10n', 'en-US.pak')
);
// The last argument must have a leading dot for the subdirectory not to
// be present in the archive, but path.join removes it, so it's prefixed.
return child_process.execFileSync(sevenzip_path, [
'a',
'-r',
dest_path,
'.' + path.sep + path.join(source_path, '*')
]);
// Translation files.
[
'es', 'ru', 'fr', 'zh_CN', 'pl', 'pt_BR', 'fi', 'de', 'da', 'ko',
].forEach((lang) => {
fs.mkdirsSync(path.join(tempPath, 'resources', 'l10n', lang, 'LC_MESSAGES'));
fs.copySync(
path.join(rootPath, 'resources', 'l10n', lang, 'LC_MESSAGES', 'loot.mo'),
path.join(tempPath, 'resources', 'l10n', lang, 'LC_MESSAGES', 'loot.mo')
);
});
// UI files.
fs.mkdirsSync(path.join(tempPath, 'resources', 'ui', 'css'));
fs.copySync(
path.join(releasePath, 'resources', 'ui', 'index.html'),
path.join(tempPath, 'resources', 'ui', 'index.html')
);
fs.copySync(
path.join(rootPath, 'resources', 'ui', 'css', 'dark-theme.css'),
path.join(tempPath, 'resources', 'ui', 'css', 'dark-theme.css')
);
fs.copySync(
path.join(rootPath, 'resources', 'ui', 'fonts'),
path.join(tempPath, 'resources', 'ui', 'fonts')
);
// Docs.
fs.mkdirsSync(path.join(tempPath, 'docs'));
[
'images',
'licenses',
'LOOT Metadata Syntax.html',
'LOOT Readme.html',
].forEach((item) => {
fs.copySync(
path.join(rootPath, 'docs', item),
path.join(tempPath, 'docs', item)
);
});
// Now compress the folder to a 7-zip archive.
compress(tempPath, destPath);
// Finally, delete the temporary folder.
fs.removeSync(tempPath);
}
function createAppArchive(release_path, dest_path) {
// Ensure that the output directory is empty.
fs.emptyDirSync(temp_path);
function createApiArchive(rootPath, binaryPath, tempPath, destPath) {
// Ensure that the output directory is empty.
fs.emptyDirSync(tempPath);
// Copy LOOT exectuable and CEF files.
var binaries = [];
if (os.platform() == 'win32') {
binaries = [
'LOOT.exe',
'd3dcompiler_47.dll',
'libEGL.dll',
'libGLESv2.dll',
'libcef.dll',
'natives_blob.bin',
'snapshot_blob.bin',
'cef.pak',
'cef_100_percent.pak',
'cef_200_percent.pak',
'devtools_resources.pak',
'icudtl.dat'
];
// API binary/binaries.
fs.copySync(
binaryPath,
path.join(tempPath, path.basename(binaryPath))
);
if (helpers.fileExists(path.join(release_path, 'wow_helper.exe'))) {
binaries.push('wow_helper.exe');
}
} else {
binaries = [
'LOOT',
'chrome-sandbox',
'libcef.so',
'natives_blob.bin',
'snapshot_blob.bin',
'cef.pak',
'cef_100_percent.pak',
'cef_200_percent.pak',
'devtools_resources.pak',
'icudtl.dat'
];
}
binaries.forEach(function(file){
fs.copySync(
path.join(release_path, file),
path.join(temp_path, file)
);
});
// API header file.
fs.mkdirsSync(path.join(tempPath, 'include', 'loot'));
fs.copySync(
path.join(rootPath, 'include', 'loot', 'api.h'),
path.join(tempPath, 'include', 'loot', 'api.h')
);
// CEF locale file.
fs.mkdirsSync(path.join(temp_path, 'resources', 'l10n'));
fs.copySync(
path.join(release_path, 'resources', 'l10n', 'en-US.pak'),
path.join(temp_path, 'resources', 'l10n', 'en-US.pak')
);
// Docs.
fs.mkdirsSync(path.join(tempPath, 'docs'));
fs.copySync(
path.join(rootPath, 'docs', 'latex', 'refman.pdf'),
path.join(tempPath, 'docs', 'readme.pdf')
);
fs.copySync(
path.join(rootPath, 'docs', 'licenses'),
path.join(tempPath, 'docs', 'licenses')
);
// Translation files.
[
'es', 'ru', 'fr', 'zh_CN', 'pl',
'pt_BR', 'fi', 'de', 'da', 'ko'
].forEach(function(lang){
fs.mkdirsSync(path.join(temp_path, 'resources', 'l10n', lang, 'LC_MESSAGES'));
fs.copySync(
path.join(root_path, 'resources', 'l10n', lang, 'LC_MESSAGES', 'loot.mo'),
path.join(temp_path, 'resources', 'l10n', lang, 'LC_MESSAGES', 'loot.mo')
);
});
// Now compress the folder to a 7-zip archive.
compress(tempPath, destPath);
// UI files.
fs.mkdirsSync(path.join(temp_path, 'resources', 'ui', 'css'));
fs.copySync(
path.join(release_path, 'resources', 'ui', 'index.html'),
path.join(temp_path, 'resources', 'ui', 'index.html')
);
fs.copySync(
path.join(root_path, 'resources', 'ui', 'css', 'dark-theme.css'),
path.join(temp_path, 'resources', 'ui', 'css', 'dark-theme.css')
);
fs.copySync(
path.join(root_path, 'resources', 'ui', 'fonts'),
path.join(temp_path, 'resources', 'ui', 'fonts')
);
// Docs.
fs.mkdirsSync(path.join(temp_path, 'docs'));
[
'images',
'licenses',
'LOOT Metadata Syntax.html',
'LOOT Readme.html'
].forEach(function(item){
fs.copySync(
path.join(root_path, 'docs', item),
path.join(temp_path, 'docs', item)
);
});
// Now compress the folder to a 7-zip archive.
compress(temp_path, dest_path);
// Finally, delete the temporary folder.
fs.removeSync(temp_path);
// Finally, delete the temporary folder.
fs.removeSync(tempPath);
}
function createApiArchive(binary_path, dest_path) {
// Ensure that the output directory is empty.
fs.emptyDirSync(temp_path);
let rootPath = '.';
if (process.argv.length > 2) {
rootPath = process.argv[2];
}
const tempPath = path.join(rootPath, 'build', 'archive.tmp');
// API binary/binaries.
fs.copySync(
binary_path,
path.join(temp_path, path.basename(binary_path))
);
const gitDesc = getGitDescription();
vulcanize(rootPath);
// API header file.
fs.mkdirsSync(path.join(temp_path, 'include', 'loot'));
fs.copySync(
path.join(root_path, 'include', 'loot', 'api.h'),
path.join(temp_path, 'include', 'loot', 'api.h')
);
// Docs.
fs.mkdirsSync(path.join(temp_path, 'docs'));
fs.copySync(
path.join(root_path, 'docs', 'latex', 'refman.pdf'),
path.join(temp_path, 'docs', 'readme.pdf')
);
fs.copySync(
path.join(root_path, 'docs', 'licenses'),
path.join(temp_path, 'docs', 'licenses')
);
// Now compress the folder to a 7-zip archive.
compress(temp_path, dest_path);
// Finally, delete the temporary folder.
fs.removeSync(temp_path);
const releasePaths = helpers.getAppReleasePaths(rootPath);
for (let i = 0; i < releasePaths.length; ++i) {
if (releasePaths[i].label) {
createAppArchive(rootPath, releasePaths[i].path, tempPath, path.join(rootPath, 'build', 'LOOT ' + gitDesc + ' (' + releasePaths[i].label + ').7z'));
} else {
createAppArchive(releasePaths[i].path, path.join(rootPath, 'build', 'LOOT ' + gitDesc + '.7z'));
}
}
if (process.argv.length < 3) {
var root_path = '.';
} else {
var root_path = process.argv[2];
}
var temp_path = path.join(root_path, 'build', 'archive.tmp');
var git_desc = getGitDescription();
vulcanize();
var release_paths = helpers.getAppReleasePaths(root_path);
for (var i = 0; i < release_paths.length; ++i) {
if (release_paths[i].label) {
createAppArchive(release_paths[i].path, path.join(root_path, 'build', 'LOOT ' + git_desc + ' (' + release_paths[i].label + ').7z'));
} else {
createAppArchive(release_paths[i].path, path.join(root_path, 'build', 'LOOT ' + git_desc + '.7z'));
}
}
var binary_paths = helpers.getApiBinaryPaths(root_path);
for (var i = 0; i < binary_paths.length; ++i) {
createApiArchive(binary_paths[i].path, path.join(root_path, 'build', 'LOOT API ' + git_desc + ' (' + binary_paths[i].label + ').7z'));
const binaryPaths = helpers.getApiBinaryPaths(rootPath);
for (let i = 0; i < binaryPaths.length; ++i) {
createApiArchive(rootPath, binaryPaths[i].path, tempPath, path.join(rootPath, 'build', 'LOOT API ' + gitDesc + ' (' + binaryPaths[i].label + ').7z'));
}
+93 -90
View File
@@ -1,113 +1,116 @@
// Helper functions shared across scripts.
var path = require('path');
var fs = require('fs');
var os = require('os');
'use strict';
const path = require('path');
const fs = require('fs');
const os = require('os');
function fileExists(file_path) {
try {
// Query the entry
stats = fs.lstatSync(file_path);
function fileExists(filePath) {
try {
// Query the entry
const stats = fs.lstatSync(filePath);
// Is it a directory?
if (stats.isFile()) {
return true;
}
} catch (e) {}
// Is it a directory?
if (stats.isFile()) {
return true;
}
} catch (e) {
/* Don't do anything, it's not an error. */
}
return false;
return false;
}
function getAppReleasePaths(root_path) {
var paths = [];
var file = 'LOOT';
var paths_to_try = [
{
path: path.join(root_path, 'build'),
label: null
},
{
path: path.join(root_path, 'build', '32'),
label: '32 bit'
},
{
path: path.join(root_path, 'build', '64'),
label: '64 bit'
}
];
function getAppReleasePaths(rootPath) {
const paths = [];
const pathsToTry = [
{
path: path.join(rootPath, 'build'),
label: null,
},
{
path: path.join(rootPath, 'build', '32'),
label: '32 bit',
},
{
path: path.join(rootPath, 'build', '64'),
label: '64 bit',
},
];
if (os.platform() == 'win32') {
file += '.exe';
let file = 'LOOT';
if (os.platform() === 'win32') {
file += '.exe';
}
for (let i = 0; i < pathsToTry.length; ++i) {
if (os.platform() === 'win32') {
pathsToTry[i].path = path.join(pathsToTry[i].path, 'Release');
}
for (var i = 0; i < paths_to_try.length; ++i) {
if (os.platform() == 'win32') {
paths_to_try[i].path = path.join(paths_to_try[i].path, 'Release');
}
if (fileExists(path.join(paths_to_try[i].path, file))) {
paths.push(paths_to_try[i]);
}
if (fileExists(path.join(pathsToTry[i].path, file))) {
paths.push(pathsToTry[i]);
}
}
return paths;
return paths;
}
function getApiBinaryPaths(root_path) {
var paths = [];
var files = [];
var paths_to_try = [
function getApiBinaryPaths(rootPath) {
const paths = [];
const pathsToTry = [
{
path: path.join(rootPath, 'build'),
label: null,
},
{
path: path.join(rootPath, 'build', '32'),
label: '32 bit',
},
{
path: path.join(rootPath, 'build', '64'),
label: '64 bit',
},
];
for (let i = 0; i < pathsToTry.length; ++i) {
let files = [];
if (os.platform() === 'win32') {
pathsToTry[i].path = path.join(pathsToTry[i].path, 'Release');
files = [
{
path: path.join(root_path, 'build'),
label: null
name: 'loot32.dll',
label: '32 bit',
},
{
path: path.join(root_path, 'build', '32'),
label: '32 bit'
name: 'loot64.dll',
label: '64 bit',
},
];
} else {
files = [
{
name: 'libloot32.so',
label: '32 bit',
},
{
path: path.join(root_path, 'build', '64'),
label: '64 bit'
}
];
for (var i = 0; i < paths_to_try.length; ++i) {
if (os.platform() == 'win32') {
paths_to_try[i].path = path.join(paths_to_try[i].path, 'Release');
files = [
{
name: 'loot32.dll',
label: '32 bit'
},
{
name: 'loot64.dll',
label: '64 bit'
}
];
} else {
files = [
{
name: 'libloot32.so',
label: '32 bit'
},
{
name: 'libloot64.so',
label: '64 bit'
}
];
}
for (var j = 0; j < files.length; ++j) {
if (fileExists(path.join(paths_to_try[i].path, files[j].name))) {
paths_to_try[i].path = path.join(paths_to_try[i].path, files[j].name);
paths_to_try[i].label = files[j].label;
paths.push(paths_to_try[i]);
break;
}
}
name: 'libloot64.so',
label: '64 bit',
},
];
}
return paths;
for (let j = 0; j < files.length; ++j) {
if (fileExists(path.join(pathsToTry[i].path, files[j].name))) {
pathsToTry[i].path = path.join(pathsToTry[i].path, files[j].name);
pathsToTry[i].label = files[j].label;
paths.push(pathsToTry[i]);
break;
}
}
}
return paths;
}
module.exports.fileExists = fileExists;
-5
View File
@@ -1,5 +0,0 @@
{
"excludes": {
"styles": [ "css/theme.css" ]
}
}
+36 -37
View File
@@ -1,44 +1,43 @@
#!/usr/bin/env node
// Build the UI's index.html file. Takes one argument, which is the path to the
// repository's root.
var child_process = require('child_process');
var path = require('path');
var fs = require('fs');
var os = require('os');
var helpers = require('./helpers');
'use strict';
const path = require('path');
const fs = require('fs');
const helpers = require('./helpers');
const vulcanize = require('vulcanize');
if (process.argv.length < 3) {
var root_path = '.';
} else {
var root_path = process.argv[2];
function runVulcanize(err) {
if (err) {
console.error(err);
process.exit(1);
}
vulcanize.processDocument();
}
var release_paths = helpers.getAppReleasePaths(root_path);
for (var i = 0; i < release_paths.length; ++i) {
var output_path = path.join(release_paths[i].path, 'resources', 'ui');
// Makes sure output directory exists first.
try {
fs.mkdirSync(output_path);
} catch (e) {
if (e.code != 'EEXIST') {
console.log(e);
}
}
var vulcanize = path.join(root_path, 'node_modules', '.bin', 'vulcanize');
if (os.platform() == 'win32') {
vulcanize += '.cmd';
}
child_process.execFileSync(vulcanize, [
'--inline',
'--strip',
'--config',
path.join(root_path, 'scripts', 'vulcanize.config.json'),
'-o',
path.join(output_path, 'index.html'),
path.join(root_path, 'src', 'gui', 'html', 'index.html')
]);
let rootPath = '.';
if (process.argv.length > 2) {
rootPath = process.argv[2];
}
helpers.getAppReleasePaths(rootPath).forEach((releasePath) => {
const outputPath = path.join(releasePath.path, 'resources', 'ui');
// Makes sure output directory exists first.
try {
fs.mkdirSync(outputPath);
} catch (e) {
if (e.code !== 'EEXIST') {
console.log(e);
}
}
vulcanize.setOptions({
inline: true,
excludes: {
styles: ['css/theme.css'],
},
output: path.join(outputPath, 'index.html'),
input: path.join(rootPath, 'src', 'gui', 'html', 'index.html'),
}, runVulcanize);
})
+6 -6
View File
@@ -488,12 +488,12 @@ namespace loot {
// First sort out the priority value. This is only given if it was changed.
BOOST_LOG_TRIVIAL(trace) << "Calculating userlist metadata priority value from Javascript variables.";
if (pluginMetadata["modPriority"] && pluginMetadata["isGlobalPriority"]) {
if (pluginMetadata["priority"] && pluginMetadata["isPriorityGlobal"]) {
BOOST_LOG_TRIVIAL(trace) << "Priority value was changed, recalculating...";
// Priority value was changed, so add it to the userlist data.
newUserlistEntry.Priority(pluginMetadata["modPriority"].as<int>());
newUserlistEntry.Priority(pluginMetadata["priority"].as<int>());
newUserlistEntry.SetPriorityExplicit(true);
newUserlistEntry.SetPriorityGlobal(pluginMetadata["isGlobalPriority"].as<bool>());
newUserlistEntry.SetPriorityGlobal(pluginMetadata["isPriorityGlobal"].as<bool>());
}
else {
// Priority value wasn't changed, use the existing userlist value.
@@ -1056,8 +1056,8 @@ namespace loot {
// Now add to pluginNode.
YAML::Node pluginNode;
pluginNode["name"] = tempPlugin.Name();
pluginNode["modPriority"] = tempPlugin.Priority();
pluginNode["isGlobalPriority"] = tempPlugin.IsPriorityGlobal();
pluginNode["priority"] = tempPlugin.Priority();
pluginNode["isPriorityGlobal"] = tempPlugin.IsPriorityGlobal();
pluginNode["messages"] = tempPlugin.Messages();
pluginNode["tags"] = tempPlugin.Tags();
pluginNode["isDirty"] = isDirty;
@@ -1108,6 +1108,6 @@ namespace loot {
void Handler::SendProgressUpdate(CefRefPtr<CefFrame> frame, const std::string& message) {
BOOST_LOG_TRIVIAL(trace) << "Sending progress update: " << message;
frame->ExecuteJavaScript("showProgress('" + message + "');", frame->GetURL(), 0);
frame->ExecuteJavaScript("loot.Dialog.showProgress('" + message + "');", frame->GetURL(), 0);
}
}
+1 -4
View File
@@ -35,12 +35,9 @@ html /deep/ ::-webkit-scrollbar-track {
html /deep/ ::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.26);
}
paper-button[autofocus] {
html /deep/ paper-button[autofocus] {
color: #64B5F6;
}
.hidden {
display:none;
}
a {
color: #2196F3;
text-decoration: none;
+20 -32
View File
@@ -16,74 +16,62 @@ was pressed.
<link rel="import" href="../../../../bower_components/paper-button/paper-button.html">
<link rel="import" href="loot-dialog.html">
<polymer-element name="loot-message-dialog" extends="loot-dialog">
<polymer-element name="loot-message-dialog">
<template>
<style>
:host {
#dialog {
max-width: 50%;
}
</style>
<shadow></shadow>
<loot-dialog id="dialog">
<content></content>
<paper-button id="confirm" affirmative autofocus>OK</paper-button>
<paper-button id="dismiss" dismissive>Cancel</paper-button>
</loot-dialog>
</template>
<script>
Polymer({
closeCallback: undefined,
setButtonText: function(accept, cancel) {
this.getElementsByClassName('accept')[0].textContent = accept;
this.getElementsByClassName('cancel')[0].textContent = cancel;
setConfirmText: function(confirmText) {
this.shadowRoot.getElementById('confirm').textContent = confirmText;
},
if (!cancel) {
this.getElementsByClassName('cancel')[0].classList.toggle('hidden', true);
} else {
this.getElementsByClassName('cancel')[0].classList.toggle('hidden', false);
}
setDismissable: function(isDialogDismissable) {
this.shadowRoot.getElementById('dismiss').hidden = !isDialogDismissable;
},
onButtonClick: function(evt) {
if (evt.target.parentElement.closeCallback) {
evt.target.parentElement.closeCallback(evt.target.classList.contains('accept'));
evt.target.parentElement.closeCallback(evt.target.id === 'confirm');
}
evt.target.parentElement.addEventListener('core-overlay-close-completed', function(evt){
evt.target.parentElement.parentNode.host.addEventListener('core-overlay-close-completed', function(evt){
evt.target.parentElement.removeChild(evt.target);
}, false);
},
showModal: function(title, text, closeCallback) {
this.heading = title;
this.querySelector('.message').textContent = text;
this.getElementsByClassName('message')[0].textContent = text;
this.closeCallback = closeCallback;
this.super();
this.shadowRoot.getElementById('dialog').showModal();
},
created: function() {
var p = document.createElement('p');
p.className = 'message';
this.appendChild(p);
var accept = document.createElement('paper-button');
accept.className = 'accept';
accept.setAttribute('affirmative', true);
accept.setAttribute('autofocus', true);
accept.textContent = 'Apply';
this.appendChild(accept);
var cancel = document.createElement('paper-button');
cancel.className = 'cancel';
cancel.setAttribute('dismissive', true);
cancel.textContent = 'Cancel';
this.appendChild(cancel);
},
attached: function() {
this.getElementsByClassName('accept')[0].addEventListener('click', this.onButtonClick, false);
this.getElementsByClassName('cancel')[0].addEventListener('click', this.onButtonClick, false);
this.shadowRoot.getElementById('confirm').addEventListener('click', this.onButtonClick, false);
this.shadowRoot.getElementById('dismiss').addEventListener('click', this.onButtonClick, false);
},
detached: function() {
this.getElementsByClassName('accept')[0].removeEventListener('click', this.onButtonClick, false);
this.getElementsByClassName('cancel')[0].removeEventListener('click', this.onButtonClick, false);
this.shadowRoot.getElementById('confirm').removeEventListener('click', this.onButtonClick, false);
this.shadowRoot.getElementById('dismiss').removeEventListener('click', this.onButtonClick, false);
},
});
+20 -8
View File
@@ -116,8 +116,6 @@ loot-clear-metadata
font-weight: 400;
font-size: 1rem;
}
.hidden,
content::content > .hidden,
:host-context(#main[data-hide-crc]) content::content > .crc,
:host-context(#main[data-hide-tag]) content::content > .tag,
:host-context(#main[data-hide-version]) content::content > .version {
@@ -220,7 +218,7 @@ loot-clear-metadata
observe: {
'data.tags': 'onTagsChange',
'data.computed.messages': 'onMessagesChange',
'data.messages': 'onMessagesChange',
'data.userlist': 'onUserlistChange',
'data.isSearchResult' : 'onSearchResultChange',
'data.isMenuOpen': 'onMenuToggle'
@@ -257,6 +255,10 @@ loot-clear-metadata
this.classList.toggle('flip');
}
/* Update version and CRC text */
this.getElementsByClassName('version')[0].textContent = this.data.getCardContent(loot.filters).version;
this.getElementsByClassName('crc')[0].textContent = this.data.getCardContent(loot.filters).crc;
/* Also initialise the non-simple-string data. */
this.onTagsChange();
this.onMessagesChange();
@@ -278,8 +280,13 @@ loot-clear-metadata
onTagsChange: function(oldValue, newValue) {
if (this.data) {
this.getElementsByClassName('tag add')[0].classList.toggle('hidden', this.data.computed.tags.added.length == 0);
this.getElementsByClassName('tag remove')[0].classList.toggle('hidden', this.data.computed.tags.removed.length == 0);
var cardContent = this.data.getCardContent(loot.filters);
var tagsAdded = this.getElementsByClassName('tag add')[0];
tagsAdded.textContent = cardContent.tags.added;
tagsAdded.hidden = cardContent.tags.added.length === 0;
var tagsRemoved = this.getElementsByClassName('tag remove')[0];
tagsRemoved.textContent = cardContent.tags.removed;
tagsRemoved.hidden = cardContent.tags.removed.length === 0;
}
},
@@ -291,10 +298,15 @@ loot-clear-metadata
messageUL.removeChild(messageUL.firstElementChild);
}
/* Now add new messages. */
this.data.computed.messages.forEach(function(message){
messageUL.appendChild(message);
var cardContent = this.data.getCardContent(loot.filters);
cardContent.messages.forEach(function(message) {
var messageLi = document.createElement('li');
messageLi.className = message.type;
// Use the Marked library for Markdown formatting support.
messageLi.innerHTML = marked(message.content);
messageUL.appendChild(messageLi);
});
messageUL.classList.toggle('hidden', this.data.computed.messages.length == 0);
messageUL.hidden = cardContent.messages.length === 0;
}
},
+23 -19
View File
@@ -125,8 +125,8 @@ loot-editor-close
</core-tooltip>
<div flex>
<h1>{{data.name}}</h1>
<span id="version">{{data.version}}</span>
<span id="crc">{{data.computed.crc}}</span>
<span id="version"></span>
<span id="crc"></span>
</div>
<core-tooltip id="isMaster" label="Master File" noarrow>
<core-icon icon="loot-custom-icons:crown"></core-icon>
@@ -250,8 +250,8 @@ loot-editor-close
data: undefined,
observe: {
'data.isGlobalPriority': 'onPriorityChange',
'data.modPriority': 'onPriorityChange',
'data.isPriorityGlobal': 'onPriorityChange',
'data.priority': 'onPriorityChange',
'data.userlist': 'onDataCacheChange',
},
@@ -318,10 +318,10 @@ loot-editor-close
/* If either of the priority values have been changed, the
base priority value they're derived from will have
changed, so record both. */
if (this.shadowRoot.getElementById('globalPriority').checked != oldData.isGlobalPriority
|| this.shadowRoot.getElementById('priorityValue').value != oldData.modPriority) {
plugin.isGlobalPriority = this.shadowRoot.getElementById('globalPriority').checked;
plugin.modPriority = this.shadowRoot.getElementById('priorityValue').value;
if (this.shadowRoot.getElementById('globalPriority').checked != oldData.isPriorityGlobal
|| this.shadowRoot.getElementById('priorityValue').value != oldData.priority) {
plugin.isPriorityGlobal = this.shadowRoot.getElementById('globalPriority').checked;
plugin.priority = this.shadowRoot.getElementById('priorityValue').value;
/* Also mark the priority as being explicitly set in the userlist. */
plugin.userlist.hasExplicitPriority = true;
}
@@ -349,7 +349,7 @@ loot-editor-close
plugin.userlist.msg = rowsData;
} else if (tables[j].parentElement.id == 'tags') {
rowsData.forEach(function(value, index, arr){
arr[index] = oldData.convTagObj(value);
arr[index] = loot.Plugin.tagFromRowData(value);
});
plugin.userlist.tag = rowsData;
} else if (tables[j].parentElement.id == 'dirty') {
@@ -391,29 +391,33 @@ loot-editor-close
that for userlist and priority data if so. */
var tempData = {};
if (newData.editor) {
if (newData.editor.isGlobalPriority) {
tempData.isGlobalPriority = newData.editor.isGlobalPriority;
if (newData.editor.isPriorityGlobal) {
tempData.isPriorityGlobal = newData.editor.isPriorityGlobal;
}
if (newData.editor.modPriority) {
tempData.modPriority = newData.editor.modPriority;
if (newData.editor.priority) {
tempData.priority = newData.editor.priority;
}
tempData.userlist = newData.editor.userlist;
} else {
tempData = {
isGlobalPriority: newData.isGlobalPriority,
modPriority: newData.modPriority,
isPriorityGlobal: newData.isPriorityGlobal,
priority: newData.priority,
userlist: newData.userlist
}
}
/* Fill in the version and CRC values. */
this.shadowRoot.getElementById('version').textContent = newData.getCardContent(loot.filters).version;
this.shadowRoot.getElementById('crc').textContent = newData.getCardContent(loot.filters).crc;
/* Fill in the editor input values. */
if (tempData.userlist && !tempData.userlist.enabled) {
this.shadowRoot.getElementById('enableEdits').checked = false;
} else {
this.shadowRoot.getElementById('enableEdits').checked = true;
}
this.shadowRoot.getElementById('globalPriority').checked = tempData.isGlobalPriority;
this.shadowRoot.getElementById('priorityValue').value = tempData.modPriority;
this.shadowRoot.getElementById('globalPriority').checked = tempData.isPriorityGlobal;
this.shadowRoot.getElementById('priorityValue').value = tempData.priority;
/* Clear then fill in editor table data. Masterlist-originated
rows should have their contents made read-only. */
@@ -493,14 +497,14 @@ loot-editor-close
if (newData.masterlist && newData.masterlist.tag) {
newData.masterlist.tag.forEach(function(tag) {
var tagData = newData.convTagObj(tag);
var tagData = loot.Plugin.tagToRowData(tag);
var row = tables[j].addRow(tagData);
tables[j].setReadOnly(row);
}, newData);
}
if (tempData.userlist && tempData.userlist.tag) {
tempData.userlist.tag.forEach(function(tag) {
var tagData = Plugin.prototype.convTagObj(tag);
var tagData = loot.Plugin.tagToRowData(tag);
tables[j].addRow(tagData);
}, tempData);
}
+6 -11
View File
@@ -140,8 +140,8 @@
observe: {
'data.userlist': 'onUserlistChange',
'data.modPriority': 'onPriorityChange',
'data.isGlobalPriority': 'onPriorityIsGlobalChange',
'data.priority': 'onPriorityChange',
'data.isPriorityGlobal': 'onPriorityIsGlobalChange',
'data.isEditorOpen': 'onEditorStateChange',
},
@@ -163,21 +163,16 @@
},
onPriorityChange: function(oldValue, newValue) {
if (this.data && this.data.modPriority) {
this.shadowRoot.getElementById('priority').textContent = this.data.modPriority;
this.shadowRoot.getElementById('secondary').classList.remove('hidden');
if (this.data && this.data.priority) {
this.shadowRoot.getElementById('priority').textContent = this.data.priority;
} else {
this.shadowRoot.getElementById('priority').textContent = '';
this.shadowRoot.getElementById('secondary').classList.add('hidden');
}
this.shadowRoot.getElementById('secondary').hidden = !(this.data && this.data.priority);
},
onPriorityIsGlobalChange: function(oldValue, newValue) {
if (this.data && this.data.isGlobalPriority) {
this.shadowRoot.getElementById('secondary').firstElementChild.classList.remove('hidden');
} else {
this.shadowRoot.getElementById('secondary').firstElementChild.classList.add('hidden');
}
this.shadowRoot.getElementById('secondary').hidden = !(this.data && this.data.isPriorityGlobal);
},
onEditorStateChange: function(oldValue, newValue) {
+7 -32
View File
@@ -29,13 +29,10 @@ searchTarget is the ID of the core-list element to search the elements of.
font-size: 0.857rem;
color: rgba(255, 255, 255, 0.7);
}
.hidden {
display: none;
}
</style>
<core-toolbar>
<paper-input id="search" label="Search cards" flex></paper-input>
<div id="count" class="caption hidden">
<div id="count" class="caption" hidden>
{{currentResult + 1}}/{{numResults}}
</div>
<paper-icon-button id="prev" icon="expand-less" disabled></paper-icon-button>
@@ -125,7 +122,7 @@ searchTarget is the ID of the core-list element to search the elements of.
var host = evt.target.parentElement.parentNode.host;
host.resetResults();
host.shadowRoot.getElementById('count').classList.toggle('hidden', !evt.target.value);
host.shadowRoot.getElementById('count').hidden = !evt.target.value;
if (!evt.target.value) {
return;
@@ -135,32 +132,10 @@ searchTarget is the ID of the core-list element to search the elements of.
var crcHidden = document.getElementById('hideCRCs').checked;
var bashTagHidden = document.getElementById('hideBashTags').checked;
document.getElementById(host.searchTarget).data.forEach(function(plugin, index){
if (plugin.name.toLowerCase().indexOf(needle) != -1
|| (!versionHidden && plugin.version.toLowerCase().indexOf(needle) != -1)
|| (!crcHidden && plugin.getCrcString().toLowerCase().indexOf(needle) != -1)) {
host.results.push(index);
plugin.isSearchResult = true;
return;
}
if (!bashTagHidden) {
var tags = plugin.getTagStrings();
if (tags.added.toLowerCase().indexOf(needle) != -1
|| tags.removed.toLowerCase().indexOf(needle) != -1) {
host.results.push(index);
plugin.isSearchResult = true;
return;
}
}
for (var i = 0; i < plugin.computed.messages.length; ++i) {
if (plugin.computed.messages[i].textContent.toLowerCase().indexOf(needle) != -1) {
host.results.push(index);
plugin.isSearchResult = true;
return;
}
if (plugin.getCardContent(loot.filters).containsText(needle)) {
host.results.push(index);
plugin.isSearchResult = true;
return;
}
});
@@ -187,7 +162,7 @@ searchTarget is the ID of the core-list element to search the elements of.
onClose: function(evt) {
evt.target.parentElement.parentNode.host.resetResults();
evt.target.parentElement.parentNode.getElementById('search').value = '';
evt.target.parentElement.parentNode.getElementById('count').classList.toggle('hidden', true);
evt.target.parentElement.parentNode.getElementById('count').hidden = true;
evt.target.dispatchEvent(new CustomEvent('loot-search-close'));
},
});
+14 -10
View File
@@ -101,8 +101,8 @@
<core-tooltip label="Update Masterlist" noarrow>
<paper-icon-button id="updateMasterlistButton" icon="file-download"></paper-icon-button>
</core-tooltip>
<paper-button id="applySortButton" class="hidden">Apply</paper-button>
<paper-button id="cancelSortButton" class="hidden">Cancel</paper-button>
<paper-button id="applySortButton" hidden>Apply</paper-button>
<paper-button id="cancelSortButton" hidden>Cancel</paper-button>
<core-tooltip label="Search Cards" noarrow>
<paper-icon-button id="showSearch" icon="search"></paper-icon-button>
</core-tooltip>
@@ -213,10 +213,10 @@
<template>
<loot-plugin-card data="{{model}}" id="{{model.id}}" data-active="{{model.isActive}}" data-empty="{{model.isEmpty}}" data-archive="{{model.loadsArchive}}" data-master="{{model.isMaster}}">
<h1>{{model.name}}</h1>
<span class="version">{{model.version}}</span>
<span class="crc">{{model.computed.crc}}</span>
<span class="tag add">{{model.computed.tags.added}}</span>
<span class="tag remove">{{model.computed.tags.removed}}</span>
<span class="version"></span>
<span class="crc"></span>
<span class="tag add"></span>
<span class="tag remove"></span>
<ul></ul>
</loot-plugin-card>
</template>
@@ -315,11 +315,15 @@
<script src="../../../bower_components/marked/lib/marked.js"></script>
<script src="../../../bower_components/Jed/jed.js"></script>
<script src="../../../bower_components/jed-gettext-parser/jedGettextParser.js"></script>
<script src="js/dialog.js"></script>
<script src="js/dom.js"></script>
<script src="js/events.js"></script>
<script src="js/filters.js"></script>
<script src="js/game.js"></script>
<script src="js/helpers.js"></script>
<script src="js/l10n.js"></script>
<script src="js/plugin.js"></script>
<script src="js/helpers.js"></script>
<script src="js/loot.js"></script>
<script src="js/filters.js"></script>
<script src="js/events.js"></script>
<script src="js/query.js"></script>
<script src="js/translator.js"></script>
<script src="js/init.js"></script>
</body>
+48
View File
@@ -0,0 +1,48 @@
'use strict';
(function exportModule(root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], factory);
} else {
// Browser globals
root.loot = root.loot || {};
root.loot.Dialog = factory();
}
}(this, () => {
return class Dialog {
static showProgress(text) {
const progressDialog = document.getElementById('progressDialog');
progressDialog.getElementsByTagName('p')[0].textContent = text;
if (!progressDialog.opened) {
progressDialog.showModal();
}
}
static closeProgress() {
const progressDialog = document.getElementById('progressDialog');
if (progressDialog.opened) {
progressDialog.close();
}
}
static showMessage(title, text) {
const dialog = document.createElement('loot-message-dialog');
dialog.setDismissable(false);
dialog.showModal(title, text);
document.body.appendChild(dialog);
}
static askQuestion(title, text, confirmText, closeCallback) {
const dialog = document.createElement('loot-message-dialog');
dialog.setConfirmText(confirmText);
dialog.showModal(title, text, closeCallback);
document.body.appendChild(dialog);
}
static showNotification(text) {
const toast = document.getElementById('toast');
toast.text = text;
toast.show();
}
};
}));
+89
View File
@@ -0,0 +1,89 @@
'use strict';
(function exportModule(root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], factory);
} else {
// Browser globals
root.loot = root.loot || {};
root.loot.dom = factory();
}
}(this, () => {
return {
getElementInTableRowTemplate(rowTemplateId, elementClass) {
const select = document.querySelector('link[rel="import"][href$="editable-table.html"]');
if (select) {
return select.import.querySelector('#' + rowTemplateId).content.querySelector('.' + elementClass);
}
return document.querySelector('#' + rowTemplateId).content.querySelector('.' + elementClass);
},
show(elementId) {
document.getElementById(elementId).hidden = false;
},
hide(elementId) {
document.getElementById(elementId).hidden = true;
},
updateSelectedGame(gameFolder) {
document.getElementById('gameMenu').value = gameFolder;
/* Also disable deletion of the game's row in the settings dialog. */
const table = document.getElementById('gameTable');
for (let i = 0; i < table.tBodies[0].rows.length; ++i) {
const folderElements = table.tBodies[0].rows[i].getElementsByClassName('folder');
if (folderElements.length === 1) {
table.setReadOnly(table.tBodies[0].rows[i], ['delete'], folderElements[0].value === gameFolder);
}
}
},
updateEnabledGames(installedGames) {
const gameMenuItems = document.getElementById('gameMenu').children;
for (let i = 0; i < gameMenuItems.length; ++i) {
if (installedGames.indexOf(gameMenuItems[i].getAttribute('value')) === -1) {
gameMenuItems[i].setAttribute('disabled', true);
} else {
gameMenuItems[i].removeAttribute('disabled');
}
}
},
updateSettingsDialog(settings, installedGames, gameFolder) {
const gameSelect = document.getElementById('defaultGameSelect');
const gameMenu = document.getElementById('gameMenu');
const gameTable = document.getElementById('gameTable');
/* First make sure game listing elements don't have any existing entries. */
while (gameSelect.children.length > 1) {
gameSelect.removeChild(gameSelect.lastElementChild);
}
while (gameMenu.firstElementChild) {
gameMenu.removeChild(gameMenu.firstElementChild);
}
gameTable.clear();
/* Now fill with new values. */
settings.games.forEach((game) => {
const menuItem = document.createElement('paper-item');
menuItem.setAttribute('value', game.folder);
menuItem.setAttribute('noink', '');
menuItem.textContent = game.name;
gameMenu.appendChild(menuItem);
gameSelect.appendChild(menuItem.cloneNode(true));
const row = gameTable.addRow(game);
gameTable.setReadOnly(row, ['name', 'folder', 'type']);
});
gameSelect.value = settings.game;
document.getElementById('languageSelect').value = settings.language;
document.getElementById('enableDebugLogging').checked = settings.enableDebugLogging;
document.getElementById('updateMasterlist').checked = settings.updateMasterlist;
this.updateEnabledGames(installedGames);
this.updateSelectedGame(gameFolder);
},
};
}));
+551 -715
View File
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More