minimize web files

This commit is contained in:
Martchus 2016-02-26 01:27:57 +01:00
parent 920eddbeed
commit 86735399fd
13 changed files with 156 additions and 63 deletions

View File

@ -45,22 +45,15 @@ set(SRC_FILES
network/networkaccessmanager.cpp
)
set(WEB_FILES
web/3rdparty/bootstrap/css/bootstrap-theme.css
web/3rdparty/bootstrap/css/bootstrap-theme.css.map
web/3rdparty/bootstrap/css/bootstrap-theme.min.css
web/3rdparty/bootstrap/css/bootstrap.css
web/3rdparty/bootstrap/css/bootstrap.css.map
web/3rdparty/bootstrap/css/bootstrap.min.css
web/3rdparty/bootstrap/fonts/glyphicons-halflings-regular.eot
web/3rdparty/bootstrap/fonts/glyphicons-halflings-regular.svg
web/3rdparty/bootstrap/fonts/glyphicons-halflings-regular.ttf
web/3rdparty/bootstrap/fonts/glyphicons-halflings-regular.woff
web/3rdparty/bootstrap/fonts/glyphicons-halflings-regular.woff2
web/3rdparty/bootstrap/js/bootstrap.js
web/3rdparty/bootstrap/js/bootstrap.min.js
web/3rdparty/bootstrap/js/npm.js
web/3rdparty/bootstrap_dropdowns_enhancement/css/dropdowns-enhancement.min.css
web/3rdparty/bootstrap_dropdowns_enhancement/js/dropdowns-enhancement.js
web/css/core.css
web/css/dashboard.css
web/js/client.js
@ -83,8 +76,8 @@ set(META_APP_AUTHOR "Martchus")
set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
set(META_APP_DESCRIPTION "Arch Linux repository browser")
set(META_VERSION_MAJOR 0)
set(META_VERSION_MINOR 1)
set(META_VERSION_PATCH 1)
set(META_VERSION_MINOR 2)
set(META_VERSION_PATCH 0)
# stringification of meta data
set(META_PROJECT_NAME_STR "\"${META_PROJECT_NAME}\"")
@ -142,6 +135,10 @@ add_definitions(
-D_GLIBCXX_USE_CXX11_ABI=0
-DCMAKE_BUILD
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DDEBUG_BUILD)
message(STATUS "Debug build enabled.")
endif()
# executable and linking
add_executable(${META_PROJECT_NAME} ${HEADER_FILES} ${SRC_FILES} ${WEB_FILES} ${RES_FILES})
@ -150,6 +147,78 @@ set_target_properties(${META_PROJECT_NAME} PROPERTIES
CXX_STANDARD 11
)
# add install target for web files / minimizing
# -> don't minimize debug builds
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
# find JavaScript/CSS minimizer
find_program(YUI_EXECUTABLE yuicompressor)
if(YUI_EXECUTABLE)
set(JS_MIN_EXECUTABLE "${CMAKE_CURRENT_SOURCE_DIR}/jsmin.sh")
endif()
if(NOT JS_MIN_EXECUTABLE)
message(STATUS "YUI compressor not found -> installing JavaScript/CSS files unminimized")
endif()
# find html minimizer
find_program(HTML_MIN_EXECUTABLE htmlmin)
endif()
if(NOT HTML_MIN_EXECUTABLE)
message(STATUS "htmlmin not found -> installing HTML files unminimized")
# install unminimized index.html
install(
FILES "${PROJECT_BINARY_DIR}/web/index.html"
DESTINATION share/${META_PROJECT_NAME}/web
COMPONENT web
)
else()
# minimize index.html
set(MIN_FILE "${PROJECT_BINARY_DIR}/web/index.min/index.html")
add_custom_command(
OUTPUT ${MIN_FILE}
COMMAND "${HTML_MIN_EXECUTABLE}"
ARGS "${HTML_MIN_EXECUTABLE}" "${PROJECT_BINARY_DIR}/web/index.html" "${MIN_FILE}"
)
install(
FILES ${MIN_FILE}
DESTINATION share/${META_PROJECT_NAME}/web
COMPONENT web
)
list(APPEND HTML_MIN_FILES "${MIN_FILE}")
endif()
foreach(WEB_FILE ${WEB_FILES})
# check whether file can be minimized
get_filename_component(WEB_DIR ${WEB_FILE} DIRECTORY)
get_filename_component(WEB_EXT ${WEB_FILE} EXT)
if(JS_MIN_EXECUTABLE AND (${WEB_EXT} STREQUAL ".js" OR ${WEB_EXT} STREQUAL ".css"))
# minimize web file
set(MIN_FILE "${CMAKE_CURRENT_BINARY_DIR}/min/${WEB_FILE}")
add_custom_command(
OUTPUT ${MIN_FILE}
COMMAND "${JS_MIN_EXECUTABLE}"
ARGS "${YUI_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/${WEB_FILE}" "${MIN_FILE}"
)
install(
FILES ${MIN_FILE}
DESTINATION share/${META_PROJECT_NAME}/${WEB_DIR}
COMPONENT web
)
list(APPEND JS_MIN_FILES "${MIN_FILE}")
else()
# install unminimized version of web file
install(
FILES ${WEB_FILE}
DESTINATION share/${META_PROJECT_NAME}/${WEB_DIR}
COMPONENT web
)
endif()
endforeach()
# add target for minimizing
if(HTML_MIN_FILES)
add_custom_target(htmlmin ALL DEPENDS ${HTML_MIN_FILES})
endif()
if(JS_MIN_FILES)
add_custom_target(jsmin ALL DEPENDS ${JS_MIN_FILES})
endif()
# add install target
install(TARGETS ${META_PROJECT_NAME}
RUNTIME DESTINATION bin
@ -163,19 +232,6 @@ install(FILES resources/settings/${META_PROJECT_NAME}.conf.js
DESTINATION share/${META_PROJECT_NAME}/skel
COMPONENT config
)
foreach(WEB_FILE ${WEB_FILES})
get_filename_component(WEB_DIR ${WEB_FILE} DIRECTORY)
install(
FILES ${WEB_FILE}
DESTINATION share/${META_PROJECT_NAME}/${WEB_DIR}
COMPONENT web
)
endforeach()
install(
FILES ${PROJECT_BINARY_DIR}/web/index.html
DESTINATION share/${META_PROJECT_NAME}/web
COMPONENT web
)
if(NOT TARGET install-binary)
add_custom_target(install-binary
DEPENDS ${META_PROJECT_NAME}

View File

@ -285,7 +285,7 @@ QJsonObject Package::basicInfo(bool includeRepoAndName) const
}
put(info, QStringLiteral("ver"), version());
put(info, QStringLiteral("desc"), description());
put(info, QStringLiteral("flagdate"), outOfDate());
put(info, QStringLiteral("fdate"), outOfDate());
put(info, QStringLiteral("arch"), buildArchitecture());
put(info, QStringLiteral("bdate"), buildDate());
put(info, QStringLiteral("archs"), architectures());

View File

@ -10,7 +10,7 @@ namespace RepoIndex {
PackageInfoLookup::PackageInfoLookup(Manager &manager, const QJsonObject &request, QObject *parent) :
PackageLookup(parent),
m_manager(manager),
m_what(request.value(QStringLiteral("what")).toString()),
m_what(request.value(QStringLiteral("w")).toString()),
m_part(Manager::None)
{
m_id = request.value(QStringLiteral("id"));
@ -54,12 +54,14 @@ PackageInfoLookup::PackageInfoLookup(Manager &manager, const QJsonObject &reques
void PackageInfoLookup::performLookup()
{
m_waitingForBusyRepos = false;
for(auto &entry : m_repos) {
if(Repository *repo = entry.first) {
const QStringList &packagesToBeRequested = entry.second;
if(repo->isBusy()) {
// repo is busy -> try again when available
connect(repo, &Repository::available, this, &PackageInfoLookup::performLookup);
m_waitingForBusyRepos = true;
} else {
// disconnect to ensure the lookup isn't done twice
disconnect(repo, nullptr, this, nullptr);

View File

@ -19,6 +19,7 @@ signals:
void resultsAvailable(const QJsonValue &what, const QJsonValue &id, const QJsonValue &value);
protected:
bool m_waitingForBusyRepos;
unsigned int m_remainingReplies;
QJsonValue m_id;
QJsonArray m_errors;
@ -27,6 +28,7 @@ protected:
inline PackageLookup::PackageLookup(QObject *parent) :
QObject(parent),
m_waitingForBusyRepos(false),
m_remainingReplies(0)
{}
@ -42,7 +44,7 @@ inline const QJsonArray &PackageLookup::results() const
inline bool PackageLookup::finished() const
{
return !m_remainingReplies && m_errors.isEmpty();
return !m_waitingForBusyRepos && !m_remainingReplies && m_errors.isEmpty();
}
#endif // PACKAGELOOKUP_H

View File

@ -30,6 +30,7 @@ SuggestionsLookup::SuggestionsLookup(Manager &manager, const QJsonObject &reques
m_errors << QStringLiteral("The specified repository \"%1\" does not exist.").arg(repoName.toString());
}
}
performLookup();
return;
}
deleteLater();
@ -37,11 +38,13 @@ SuggestionsLookup::SuggestionsLookup(Manager &manager, const QJsonObject &reques
void SuggestionsLookup::performLookup()
{
m_waitingForBusyRepos = false;
for(Repository *&repo : m_repos) {
if(repo) {
if(repo->isBusy()) {
// repo is busy -> try again when available
connect(repo, &Repository::available, this, &SuggestionsLookup::performLookup);
m_waitingForBusyRepos = true;
} else {
// disconnect to ensure the lookup isn't done twice
disconnect(repo, nullptr, this, nullptr);

View File

@ -68,16 +68,8 @@ inline const UpgradeLookupResults &UpgradeLookupProcess::results() const
*/
void UpgradeLookupProcess::requestSources()
{
// ensure the repository to check and the upgrade source are both not busy
if(m_toCheck->isBusy()) {
connect(m_toCheck, &Repository::available, this, &UpgradeLookupProcess::requestSources);
} else {
disconnect(m_toCheck, nullptr, this, nullptr);
}
if(m_upgradeSource->isBusy()) {
connect(m_upgradeSource, &Repository::available, this, &UpgradeLookupProcess::requestSources);
} else {
disconnect(m_upgradeSource, nullptr, this, nullptr);
if(ensureNotBusy()) {
return;
}
// request sources if required
switch(m_upgradeSource->requestsRequired()) {
@ -109,6 +101,9 @@ void UpgradeLookupProcess::requestSources()
*/
void UpgradeLookupProcess::sourceReady()
{
if(ensureNotBusy()) {
return;
}
// if a request was required, check whether an error occured
if(m_reply && !m_reply->error().isEmpty()) {
m_results.errors << m_reply->error();
@ -129,6 +124,28 @@ void UpgradeLookupProcess::checkUpgrades()
m_toCheck->checkForUpgrades(m_results, QList<Repository *>() << m_upgradeSource);
}
/*!
* \brief Ensures the repository to check and the upgrade source are both not busy.
* \returns Returns whether the repositories are busy. In this case the lookup will
* continue with the "step" requestSources() when the repos are available again.
*/
bool UpgradeLookupProcess::ensureNotBusy()
{
if(m_toCheck->isBusy()) {
connect(m_toCheck, &Repository::available, this, &UpgradeLookupProcess::requestSources);
return true;
} else {
disconnect(m_toCheck, nullptr, this, nullptr);
}
if(m_upgradeSource->isBusy()) {
connect(m_upgradeSource, &Repository::available, this, &UpgradeLookupProcess::requestSources);
return true;
} else {
disconnect(m_upgradeSource, nullptr, this, nullptr);
}
return false;
}
/*!
* \class UpgradeLookup
* \brief The UpgradeLookup class performs an async upgrade lookup for using multiple upgrade sources.
@ -281,7 +298,7 @@ void UpgradeLookupJson::processFinished()
if(!m_errorsArray.isEmpty()) {
results.insert(QStringLiteral("errors"), m_errorsArray);
}
emit resultsAvailable(m_request.value(QStringLiteral("what")), m_request.value(QStringLiteral("id")), results);
emit resultsAvailable(m_request.value(QStringLiteral("w")), m_request.value(QStringLiteral("id")), results);
// lookup done, delete this helper object
deleteLater();
}

View File

@ -96,6 +96,8 @@ private slots:
void checkUpgrades();
private:
bool ensureNotBusy();
const Repository *m_toCheck;
Repository *m_upgradeSource;
PackageReply *m_reply;

2
jsmin.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
mkdir -p "${3%/*}" && "$1" "$2" -o "$3"

View File

@ -40,7 +40,7 @@ void Connection::sendJson(const QJsonObject &obj)
void Connection::sendError(const QString &msg, const QJsonValue &id)
{
QJsonObject response;
response.insert(QStringLiteral("class"), QStringLiteral("error"));
response.insert(QStringLiteral("c"), QStringLiteral("error"));
response.insert(QStringLiteral("msg"), msg);
if(!id.isNull() && !id.isUndefined()) {
response.insert(QStringLiteral("id"), id);
@ -51,9 +51,9 @@ void Connection::sendError(const QString &msg, const QJsonValue &id)
void Connection::sendResult(const QJsonValue &what, const QJsonValue &id, const QJsonValue &value)
{
QJsonObject response;
response.insert(QStringLiteral("class"), QStringLiteral("results"));
response.insert(QStringLiteral("what"), what);
response.insert(QStringLiteral("value"), value);
response.insert(QStringLiteral("c"), QStringLiteral("results"));
response.insert(QStringLiteral("w"), what);
response.insert(QStringLiteral("v"), value);
if(!id.isNull() && !id.isUndefined()) {
response.insert("id", id);
}
@ -63,9 +63,9 @@ void Connection::sendResult(const QJsonValue &what, const QJsonValue &id, const
void Connection::sendResults(const QJsonValue &what, const QJsonValue &id, const QJsonValue &values)
{
QJsonObject response;
response.insert(QStringLiteral("class"), QStringLiteral("results"));
response.insert(QStringLiteral("what"), what);
response.insert(QStringLiteral("values"), values);
response.insert(QStringLiteral("c"), QStringLiteral("results"));
response.insert(QStringLiteral("w"), what);
response.insert(QStringLiteral("v"), values);
if(!id.isNull() && !id.isUndefined()) {
response.insert("id", id);
}
@ -89,13 +89,13 @@ void Connection::performLookup(const QJsonObject &request, Args &&...args)
if(lookup->finished()) {
// the lookup has already finished when constructing the lookup object
// -> send the results immidiately
sendResult(request.value(QStringLiteral("what")), request.value(QStringLiteral("id")), lookup->results());
sendResult(request.value(QStringLiteral("w")), request.value(QStringLiteral("id")), lookup->results());
} else if(!lookup->errors().isEmpty()) {
// error occured during the construction of the lookup object
// -> send the errors immidiately
QJsonObject results;
results.insert(QStringLiteral("errors"), lookup->errors());
sendResult(request.value(QStringLiteral("what")), request.value(QStringLiteral("id")), results);
sendResult(request.value(QStringLiteral("w")), request.value(QStringLiteral("id")), results);
} else {
// the lookup object has been created without errors but the lookup is not done yet
// -> send results when available
@ -106,7 +106,7 @@ void Connection::performLookup(const QJsonObject &request, Args &&...args)
void Connection::handleQuery(const QJsonObject &obj)
{
const auto what = obj.value(QStringLiteral("what")).toString();
const auto what = obj.value(QStringLiteral("w")).toString();
const auto id = obj.value(QStringLiteral("id"));
if(what == QLatin1String("basicrepoinfo")) {
m_repoInfoUpdatesRequested = obj.value(QStringLiteral("updates")).toBool(m_repoInfoUpdatesRequested);
@ -129,7 +129,7 @@ void Connection::handleQuery(const QJsonObject &obj)
void Connection::handleCmd(const QJsonObject &obj)
{
const auto what = obj.value(QStringLiteral("what")).toString();
const auto what = obj.value(QStringLiteral("w")).toString();
const auto id = obj.value(QStringLiteral("id"));
if(what == QLatin1String("stop")) {
if(m_socket->peerAddress().isLoopback()) {
@ -173,7 +173,7 @@ void Connection::processTextMessage(const QString &message)
const QJsonDocument doc = QJsonDocument::fromJson(jsonData, &error);
if(error.error == QJsonParseError::NoError) {
const QJsonObject obj = doc.object();
const QString msgClass = obj.value(QStringLiteral("class")).toString();
const QString msgClass = obj.value(QStringLiteral("c")).toString();
if(msgClass == QLatin1String("query")) {
handleQuery(obj);
} else if(msgClass == QLatin1String("cmd")) {

View File

@ -130,7 +130,7 @@
</colgroup>
<thead>
<tr>
<th>Arch</th><th>Repo</th><th>Name</th><th>Version</th><th>Description</th><th>Build date</th><th>Flag</th>
<th>Arch</th><th>Repo</th><th>Name</th><th>Version</th><th>Description</th><th>Build date</th>
</tr>
</thead>
<tbody id="packages" class="table-list table-list-clickable"></tbody>

View File

@ -81,12 +81,12 @@
this.socket.onmessage = function(event) {
var msg = JSON.parse(event.data);
switch(msg.class) {
switch(msg.c) {
case "error":
repoindex.pageManager.addError("Server replied error: " + msg.msg);
break;
case "results":
this.client.parseResults(msg.id, msg.what, msg.values ? msg.values : msg.value);
this.client.parseResults(msg.id, msg.w, msg.v);
break;
}
};
@ -127,8 +127,8 @@
this.scheduleRequest = function(type, params, callback) {
// add request information to params
params.class = "query";
params.what = type;
params.c = "query";
params.w = type;
// check whether the same kind of request has already been scheduled
var i = 0;
switch(type) {
@ -136,7 +136,7 @@
case repoindex.RequestType.GroupInfo:
// -> upgrade existing reuquest in this case
for(; i < this.scheduledRequests.length; ++i) {
if(this.scheduledRequests[i].params.class === "query" && this.scheduledRequests[i].params.what === type) {
if(this.scheduledRequests[i].params.c === "query" && this.scheduledRequests[i].params.w === type) {
// there is already such a request
this.scheduledRequests[i].callbacks.push(callback); // add callback
params.id = this.scheduledRequests[i].params.id; // keep the old ID
@ -262,7 +262,7 @@
this.sendCmd = function(cmd) {
if(this.isOpen()) {
this.socket.send(JSON.stringify({class: "cmd", what: cmd}));
this.socket.send(JSON.stringify({c: "cmd", w: cmd}));
} else {
repoindex.pageManager.addError("Not connected to a server.");
}
@ -374,13 +374,13 @@
var value = values[i];
var repo = repoindex.client.repos[value.repo];
if(repo) {
var package = repo.packages[value.name];
if(package) {
var pkg = repo.packages[value.name];
if(pkg) {
if(value.basics) {
package.basics = value.basics;
pkg.basics = value.basics;
}
if(value.details) {
package.details = value.details;
pkg.details = value.details;
}
} else {
repoindex.pageManager.addError("Package info replied by server refers to unknown package.");

View File

@ -14,9 +14,12 @@
// row element
this.rowElement = document.createElement("tr");
this.rowElement.entry = this;
this.rowElement.addCell = function(text) {
this.rowElement.addCell = function(text, color) {
var cellElement = document.createElement("td");
if(text) {
if(color) {
cellElement.style.color = color;
}
cellElement.appendChild(document.createTextNode(text));
}
this.appendChild(cellElement);

View File

@ -25,9 +25,15 @@
var srcOnly = this.repoEntry && this.repoEntry.info.srcOnly;
var pkgOnly = this.repoEntry && this.repoEntry.info.pkgOnly;
var version = this.curVer ? (this.curVer + " → " + (basics.ver ? basics.ver : "?")) : basics.ver;
var values = [srcOnly ? "n/a" : basics.arch, this.info.repo, this.name, version, basics.desc, srcOnly ? "n/a" : basics.bdate, pkgOnly ? "n/a" : basics.flagdate];
for(var i = 0; i < 7; ++i) {
this.rowElement.addCell(repoindex.makeStr(values[i]));
var values = [srcOnly ? "n/a" : basics.arch, this.info.repo, this.name, version, basics.desc, srcOnly ? "n/a" : basics.bdate];
if(basics.fdate) {
for(var i = 0; i < 6; ++i) {
this.rowElement.addCell(repoindex.makeStr(values[i]), i === 2 ? "red" : undefined);
}
} else {
for(var i = 0; i < 6; ++i) {
this.rowElement.addCell(repoindex.makeStr(values[i]));
}
}
};