Commit 9a28e640 authored by DFN2's avatar DFN2

revert to pling-store

parent 75abf6a9
# opendesktop-app
# Pling-Store
Pling-Store is a Content Management App for OCS-compatible websites like opendesktop.org, gnome-look.org, etc.
It allows to download and install applications, desktop themes, icon themes, wallpapers, or mouse cursors
under various desktop environments using the "Install"-button.
Currently supported are these desktop environments:
KDE Plasma, Gnome, XFCE, Mate, Cinnamon, Budgie, LXQt, Elementary and Enlightenment.
## Usage
Using the Appimage package format, it should work on any distro like Ubuntu, Debian, Arch, Suse, Redhat and many more.
### Best with AppImageLauncher
If you never used an Appimage before, we recommend this tool to make AppImages run, install/uninstall and update on your Linux OS:
https://www.pling.com/p/1228228/
*Please see if AppImageLauncher offers native packages for your distro, if not, you may request it in the issue section.*
After installing AppImageLauncher, you can simply Double-Click on the Pling-Store Appimage to run or install it.
### Manual Run
To try the Pling-Store without installing, you can simply [make it executable](https://youtu.be/nzZ6Ikc7juw?t=78) and (double-)click on it.
## Development
The Pling-Store is a regular electron app plus the [ocs-manager](https://git.opendesktop.org/akiraohgaki/ocs-manager/). The first acts as a presentation
layer and the second is the one who handles the intallation of the different products.
### Project Setup
```
npm install
curl -fsSL -o node_modules/.bin/ocs-manager https://git.opendesktop.org/akiraohgaki/ocs-manager/uploads/d3dc42436b82d11360ebc96b38d4aaf4/ocs-manager-0.8.1-1-x86_64.AppImage
chmod +x node_modules/.bin/ocs-manager
```
### AppImage Generation
`./scripts/package appimage`
{
"defaults": {
"startPage": "https://www.pling.com/",
"windowBounds": {
"x": 0,
"y": 0,
"width": 1024,
"height": 768
}
},
"updateCheckAfter": 86400000, "//": "milliseconds"
}
{
"bin": "ocs-manager",
"port": 0
}
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
.icon-ocs-store {
background-image: url(app-icons/pling-store.svg);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Security-Policy"
content="default-src 'self' 'unsafe-inline'; connect-src *">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="format-detection" content="telephone=no, email=no, address=no">
<title></title>
<link href="styles/reset.css" rel="stylesheet">
<link href="styles/color.css" rel="stylesheet">
<link href="styles/material-icons.css" rel="stylesheet">
<link href="styles/global.css" rel="stylesheet">
</head>
<body>
<app-root></app-root>
<script>
require = require('esm')(module);
module.exports = require('./scripts/renderers/browser-window.js');
</script>
</body>
</html>
/**
* Chirit
*
* @author Akira Ohgaki <akiraohgaki@gmail.com>
* @copyright 2018, Akira Ohgaki
* @license https://opensource.org/licenses/BSD-2-Clause
* @link https://github.com/akiraohgaki/chirit
*/
import Component from './Component.js';
import StateManager from './StateManager.js';
import Handler from './Handler.js';
import WebStorage from './WebStorage.js';
import Utility from './Utility.js';
export default class Chirit {
static get Component() {
return Component;
}
static get StateManager() {
return StateManager;
}
static get Handler() {
return Handler;
}
static get WebStorage() {
return WebStorage;
}
static get Utility() {
return Utility;
}
}
/**
* Chirit
*
* @author Akira Ohgaki <akiraohgaki@gmail.com>
* @copyright 2018, Akira Ohgaki
* @license https://opensource.org/licenses/BSD-2-Clause
* @link https://github.com/akiraohgaki/chirit
*/
export default class Component extends HTMLElement {
static define(name, options) {
window.customElements.define(name, this, options);
}
constructor() {
super();
this._state = {};
this._shadowRoot = null;
this._template = null;
this._updateCount = 0;
this.initShadow();
this.initTemplate();
this.init();
}
set state(state) {
this.setState(state);
}
get state() {
return this.getState();
}
get contentRoot() {
return this._shadowRoot || this.shadowRoot || this;
}
initShadow() {
this.enableShadow();
}
initTemplate() {
this.importTemplate(document.createElement('template'));
}
setState(state) {
if (typeof state !== 'object' || state === null) {
throw new TypeError(`"${state}" is not an object`);
}
const oldState = Object.assign({}, this._state);
this._state = state;
const newState = Object.assign({}, this._state);
this._stateChangedCallback(oldState, newState);
}
getState() {
return this._state;
}
setContent(content) {
// "content" should be Node object or string
if (typeof content === 'string') {
const template = document.createElement('template');
template.innerHTML = content;
content = template.content;
}
const oldContent = this.exportTemplate().content;
this._template.content.textContent = null;
this._template.content.appendChild(content);
const newContent = this.exportTemplate().content;
this.contentRoot.textContent = null;
this.contentRoot.appendChild(newContent.cloneNode(true));
this._contentChangedCallback(oldContent, newContent);
}
enableShadow(options = {}) {
this._shadowRoot = this.attachShadow(Object.assign(
{mode: 'open'},
options
));
}
importTemplate(template) {
if (!(template instanceof HTMLTemplateElement)) {
throw new TypeError(`"${template}" is not a HTMLTemplateElement`);
}
this._template = template.cloneNode(true);
}
exportTemplate() {
return this._template.cloneNode(true);
}
dispatch(type, data = {}) {
this.dispatchEvent(new CustomEvent(type, {
detail: data,
bubbles: true,
composed: true
}));
}
update(state) {
if (state !== undefined) {
this.setState(state);
}
else {
this._update();
}
}
_update() {
let content = this.render();
if (typeof content !== 'string' && !content) {
content = this.exportTemplate().content;
}
this.setContent(content);
this._updatedCallback();
}
// Abstract methods
init() {}
render() {}
// Lifecycle methods
static get componentObservedAttributes() {
return [];
}
componentAttributeChangedCallback() {}
componentConnectedCallback() {}
componentDisconnectedCallback() {}
componentAdoptedCallback() {}
componentStateChangedCallback() {}
componentContentChangedCallback() {}
componentUpdatedCallback() {}
// Lifecycle methods in parent class
static get observedAttributes() {
return this.componentObservedAttributes;
}
attributeChangedCallback(attributeName, oldValue, newValue, namespace) {
this.componentAttributeChangedCallback(attributeName, oldValue, newValue, namespace);
if (this._updateCount && oldValue !== newValue) {
this._update();
}
}
connectedCallback() {
this.componentConnectedCallback();
if (!this._updateCount) {
this._update();
}
}
disconnectedCallback() {
this.componentDisconnectedCallback();
}
adoptedCallback(oldDocument, newDocument) {
this.componentAdoptedCallback(oldDocument, newDocument);
if (!this._updateCount) {
this._update();
}
}
// Additional lifecycle methods
_stateChangedCallback(oldState, newState) {
this.componentStateChangedCallback(oldState, newState);
//if (this._updateCount && JSON.stringify(oldState) !== JSON.stringify(newState)) {
// this.update();
//}
if (this._updateCount) {
this._update();
}
}
_contentChangedCallback(oldContent, newContent) {
this.componentContentChangedCallback(oldContent, newContent);
}
_updatedCallback() {
this._updateCount++;
this.componentUpdatedCallback();
}
}
/**
* Chirit
*
* @author Akira Ohgaki <akiraohgaki@gmail.com>
* @copyright 2018, Akira Ohgaki
* @license https://opensource.org/licenses/BSD-2-Clause
* @link https://github.com/akiraohgaki/chirit
*/
export default class Handler {
constructor(handler) {
// handler:
// (data = {}, type = '') => {
// return {};
// }
this._initialHandler = handler;
this._defaultHandler = null;
this._typeHandlersCollection = new Map(); // [[type, [handler]]]
this.resetDefault();
}
resetDefault() {
this.setDefault(this._initialHandler);
return this;
}
setDefault(handler) {
this._checkTypeOfHandler(handler);
this._defaultHandler = handler;
this.defaultChangedCallback(handler);
return this;
}
add(type, handler) {
this._checkTypeOfHandler(handler);
this.beforeAddCallback(type, handler);
const typeHandlers = this._typeHandlersCollection.get(type) || new Set();
if (!typeHandlers.has(handler)) {
typeHandlers.add(handler);
this._typeHandlersCollection.set(type, typeHandlers);
this.afterAddCallback(type, handler);
}
return this;
}
remove(type, handler) {
this._checkTypeOfHandler(handler);
this.beforeRemoveCallback(type, handler);
if (this._typeHandlersCollection.has(type)) {
const typeHandlers = this._typeHandlersCollection.get(type);
if (typeHandlers.has(handler)) {
typeHandlers.delete(handler);
if (typeHandlers.size) {
this._typeHandlersCollection.set(type, typeHandlers);
}
else {
this._typeHandlersCollection.delete(type);
}
this.afterRemoveCallback(type, handler);
}
}
return this;
}
has(type) {
return this._typeHandlersCollection.has(type);
}
async invoke(data = {}, type = '') {
// This function will wrap and call registered handlers with Promise and Promise.all().
// And all return values of the same type of handlers will be combined in object finally.
// If any handler returned false, will not combine values and return null.
const promises = [];
promises.push(new Promise((resolve) => {
resolve(this._defaultHandler(data, type));
}));
if (type && this._typeHandlersCollection.has(type)) {
const typeHandlers = this._typeHandlersCollection.get(type);
for (const handler of typeHandlers) {
promises.push(new Promise((resolve) => {
resolve(handler(data, type));
}));
}
}
const values = await Promise.all(promises);
if (values.includes(false)) {
return null;
}
const combinedData = {};
for (const value of values) {
Object.assign(combinedData, value);
}
return combinedData;
}
defaultChangedCallback() {}
beforeAddCallback() {}
afterAddCallback() {}
beforeRemoveCallback() {}
afterRemoveCallback() {}
_checkTypeOfHandler(handler) {
if (typeof handler !== 'function') {
throw new TypeError(`"${handler}" is not a function`);
}
}
}
# Chirit
[![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause)
A front-end library.
Copyright: 2018, Akira Ohgaki
License: BSD-2-Clause
/**
* Chirit
*
* @author Akira Ohgaki <akiraohgaki@gmail.com>
* @copyright 2018, Akira Ohgaki
* @license https://opensource.org/licenses/BSD-2-Clause
* @link https://github.com/akiraohgaki/chirit
*/
import Handler from './Handler.js';
export default class StateManager {
constructor(target) {
// "target" should be Element object or selector string
if (typeof target === 'string') {
target = document.querySelector(target);
}
this._target = target || document;
this._state = new Map();
this._eventListener = this._eventListener.bind(this);
this._eventHandler = null;
this._actionHandler = null;
this._stateHandler = null;
this._viewHandler = null;
this._initHandlers();
}
get target() {
return this._target;
}
get state() {
return this._state;
}
get eventHandler() {
return this._eventHandler;
}
get actionHandler() {
return this._actionHandler;
}
get stateHandler() {
return this._stateHandler;
}
get viewHandler() {
return this._viewHandler;
}
dispatch(type, data = {}) {
this._target.dispatchEvent(new CustomEvent(type, {detail: data}));
}
_eventListener(event) {
event.preventDefault();
event.stopPropagation();
this._invokeHandlers(event.detail, event.type);
}
_initHandlers() {
this._eventHandler = new Handler((data) => {
return data;
});
this._actionHandler = new Handler(() => {
return {};
});
this._stateHandler = new Handler((data, type) => {
this._state.set(type, data);
return data;
});
this._viewHandler = new Handler(() => {
return {};
});
const beforeAddCallback = (type) => {
if (!this._eventHandler.has(type)
&& !this._actionHandler.has(type)
&& !this._stateHandler.has(type)
&& !this._viewHandler.has(type)
) {
this._target.addEventListener(type, this._eventListener, false);
this._state.set(type, {});
}
};
const afterRemoveCallback = (type) => {
if (!this._eventHandler.has(type)
&& !this._actionHandler.has(type)
&& !this._stateHandler.has(type)
&& !this._viewHandler.has(type)
) {
this._target.removeEventListener(type, this._eventListener, false);
this._state.delete(type);
}
};
this._eventHandler.beforeAddCallback = beforeAddCallback;
this._eventHandler.afterRemoveCallback = afterRemoveCallback;
this._actionHandler.beforeAddCallback = beforeAddCallback;
this._actionHandler.afterRemoveCallback = afterRemoveCallback;
this._stateHandler.beforeAddCallback = beforeAddCallback;
this._stateHandler.afterRemoveCallback = afterRemoveCallback;
this._viewHandler.beforeAddCallback = beforeAddCallback;
this._viewHandler.afterRemoveCallback = afterRemoveCallback;
}
async _invokeHandlers(data, type) {
try {
const eventRusult = await this._eventHandler.invoke(data, type);
if (!eventRusult) {
return;
}
const actionResult = await this._actionHandler.invoke(eventRusult, type);
if (!actionResult) {
return;
}
const stateResult = await this._stateHandler.invoke(actionResult, type);
if (!stateResult) {
return;
}
//const viewResult = await this._viewHandler.invoke(stateResult, type);
this._viewHandler.invoke(stateResult, type);
}
catch (error) {
console.error(error);
}
}
}
/**
* Chirit
*
* @author Akira Ohgaki <akiraohgaki@gmail.com>
* @copyright 2018, Akira Ohgaki
* @license https://opensource.org/licenses/BSD-2-Clause
* @link https://github.com/akiraohgaki/chirit
*/
export default class Utility {
static parseQueryString() {
const params = {};
if (window.location.search.length > 1) {
const queries = window.location.search.substring(1).split('&');
for (const query of queries) {
const kv = query.split('=');
const key = decodeURIComponent(kv[0]);
const value = (kv[1] !== undefined) ? decodeURIComponent(kv[1]) : '';
params[key] = value;
}
}
return params;
}
static convertByteToHumanReadable(byte) {
byte = parseFloat(byte);
const kb = 1024;
const mb = 1024 * kb;
const gb = 1024 * mb;
const tb = 1024 * gb;
const pb = 1024 * tb;
const eb = 1024 * pb;
const zb = 1024 * eb;
const yb = 1024 * zb;
let text = '';
if (byte < kb) {
text = `${byte.toFixed(0)} B`;
}
else if (byte < mb) {
text = `${(byte / kb).toFixed(2)} KB`;
}
else if (byte < gb) {
text = `${(byte / mb).toFixed(2)} MB`;
}
else if (byte < tb) {
text = `${(byte / gb).toFixed(2)} GB`;
}
else if (byte < pb) {
text = `${(byte / tb).toFixed(2)} TB`;
}
else if (byte < eb) {
text = `${(byte / pb).toFixed(2)} PB`;
}
else if (byte < zb) {
text = `${(byte / eb).toFixed(2)} EB`;