From ff749d68b6868fbf0af3b4a2bc1aa1e991e1465d Mon Sep 17 00:00:00 2001 From: "Marcel Kapfer (mmk2410)" Date: Thu, 2 Jun 2016 12:01:32 +0200 Subject: [PATCH] Initial commmit --- .gitignore | 35 +++++++++++++ .jshintrc | 3 ++ AUTHORS | 6 +++ CONTRIBUTING.md | 17 ++++++ LICENSE.txt | 22 ++++++++ README.md | 7 +++ bcli.sh | 3 ++ pubspec.yaml | 20 +++++++ run.sh | 44 ++++++++++++++++ web/api.dart | 119 ++++++++++++++++++++++++++++++++++++++++++ web/article-view.dart | 18 +++++++ web/article_view.html | 16 ++++++ web/index.dart | 61 ++++++++++++++++++++++ web/index.html | 57 ++++++++++++++++++++ web/main.js | 53 +++++++++++++++++++ web/package.json | 23 ++++++++ web/renderer.js | 3 ++ web/style.html | 27 ++++++++++ 18 files changed, 534 insertions(+) create mode 100644 .gitignore create mode 100644 .jshintrc create mode 100644 AUTHORS create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100755 bcli.sh create mode 100644 pubspec.yaml create mode 100644 run.sh create mode 100644 web/api.dart create mode 100644 web/article-view.dart create mode 100644 web/article_view.html create mode 100644 web/index.dart create mode 100644 web/index.html create mode 100644 web/main.js create mode 100644 web/package.json create mode 100644 web/renderer.js create mode 100644 web/style.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0dc6abf --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +node_modules +# See https://www.dartlang.org/tools/private-files.html + +# Files and directories created by pub +.buildlog +.packages +.project +.pub/ +build/ +**/packages/ + +# Files created by dart2js +# (Most Dart developers will use pub build to compile Dart, use/modify these +# rules if you intend to use dart2js directly +# Convention is to use extension '.dart.js' for Dart compiled to Javascript to +# differentiate from explicit Javascript files) +*.dart.js +*.part.js +*.js.deps +*.js.map +*.info.json + +# Directory created by dartdoc +doc/api/ + +# Don't commit pubspec lock file +# (Library packages only! Remove pattern if developing an application package) +pubspec.lock +web/packages + +# IDE files +.idea/ +*.iml +.atom/ +completer.hist diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..2b6f469 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,3 @@ +{ + "esversion": 6 +} diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..ed2d3d9 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,6 @@ +# Here is a list of people that have contributed to this project +# Please keep this form: +# +# Name / Organization + +Marcel Kapfer diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4ab4c17 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,17 @@ +# Contributing + +If you want to contribute have a look at the project board at [phab.mmk2410.org](https://phab.mmk2410.org/project/view/19/) to see what you should do. + +## Workflow + +While there is no stable release this project will follow the feature workflow. As soon as there is a stable release I will switch to the Gitflow workflow. + +If your unfamiliar with these workflows I recommend reading [this article](https://www.atlassian.com/git/tutorials/comparing-workflows/forking-workflow/). + +## Contact + +If you want to ask me some questions, feel free to contact me at (marcelmichaelkapfer@yahoo.co.nz)[mailto:marcelmichaelkapfer@yahoo.co.nz]. + +## Honor + +Please add yourself to the AUTHORS file. diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..d51ed64 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,22 @@ +COPYRIGHT (c) 2016 Marcel Kapfer (mmk2410) + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..719006f --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Rangitaki Desktop Client + +This is the Rangitaki desktop client made with Dart, Polymer and Electron. + +***It is not fully developed and misses many features. The content of this repository is right now only for development purposes, but not for any productive usage.*** + +For contributing see the CONTRIBUTING.md. diff --git a/bcli.sh b/bcli.sh new file mode 100755 index 0000000..826b60b --- /dev/null +++ b/bcli.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +rlwrap /bin/bash ./run.sh diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..d6099a0 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,20 @@ +name: rangitakidesktop +version: 0.0.1 +description: > + Desktop app for Rangitaki +author: Marcel Kapfer (mmk2410) +homepage: https://mmk2410.org/rangitaki/rangitaki-desktop/ +documentation: https://mmk2410.org/rangitaki/rangitaki-lib/docs/ + +dependencies: + browser: '>=0.10.0 <0.11.0' + http: '^0.11.3+7' + polymer_elements: ^1.0.0-rc.8 + polymer: ^1.0.0-rc.2 + web_components: ^0.12.0 + test: "^0.12.13+4" + +transformers: +- polymer: + entry_points: + - web/index.html diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..bcdec14 --- /dev/null +++ b/run.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +while true; do + echo -n " (BCLI) > " + read -r command + + case $command in + build | b ) pub build & ;; + run | r ) + killall -q electron + electron build/web/ & + ;; + bar | br ) + killall -q electron + pub build + electron build/web/ & + ;; + get | g) pub get ;; + close | c) killall -q electron ;; + test | t) pub run test;; + lint | l) + jshint web/main.js + jshint web/renderer.js + dartanalyzer web/ + ;; + exit | quit | q | x | e) + exit ;; + about ) echo "mmk2410 - Build CLI script - MIT License" ;; + help | h | ? ) + echo """ +run, r Close running instances and run Electron in background +build, b Build app in background +bar, br Short for build and run +test, t Run tests. +close, c Exit running Electron instances +exit, quit, q, x, e Exit the script +about About text +get, g Get updates. +help, h, ? Prints this help + """ + ;; + * ) echo "Command $command not found." ;; + esac +done diff --git a/web/api.dart b/web/api.dart new file mode 100644 index 0000000..3842551 --- /dev/null +++ b/web/api.dart @@ -0,0 +1,119 @@ +import 'dart:async'; +import 'dart:html'; +import 'dart:convert'; + +import 'package:polymer_elements/paper_item.dart'; + +import 'article-view.dart'; + +/** + * Easily connects with the Rangitaki API and does also a part of the frontend. + */ +class RangitakiConnect { + + String baseurl; + String _username; + String _password; + String _auth; + + /** + * Initializer for RangitaiConnect. + * @value baseurl Root URL of your Rangitaki installation. + * @value username Username for authentication. + * @value password Password for authentication. + */ + RangitakiConnect(this.baseurl, this._username, this._password) { + _auth = BASE64.encode(UTF8.encode("$_username:$_password")); + } + + /** + * Fetch all blogs from the server and list them in the #list element. + */ + Future addBlogs() async { + var data = await _getBlogs(); + data = JSON.decode(data); + for (String blog in data) { + blog = blog.substring(0, blog.length - 3); + PaperItem item = new PaperItem(); + item.text = blog; + item.id = blog; + querySelector("#main-list").children.add(item); + } + } + + /** + * Fetch all articles of a blog from the server and list the in the #list + * element. + * @value blog Blog for which the articles shoul be fetched. + */ + Future addArticles(String blog) async { + var data = await _getArticles(blog); + + data = JSON.decode(data); + for (String article in data) { + article = article.substring(0, article.length - 3); + PaperItem item = new PaperItem(); + item.text = article; + item.id = article; + querySelector("#main-list").children.add(item); + } + } + + Future showArticle(String blog, String post, ArticleView articleView) async { + var data = await _getArticle(blog, post); + + print(data); + + data = JSON.decode(data); + List tags = data['tags']; + String tag = tags.join(", "); + + print("Tags: $tag"); + + print("ArticleView: $articleView"); + + articleView + ..title = data['title'] + ..author = data['author'] + ..date = data['date'] + ..tags = tag + ..text = data['text']; + } + + /** + * Internal method for fetching blogs from the server. + */ + Future _getBlogs() async { + String _url = "$baseurl/rcc/api/list/"; + return (await + HttpRequest.request( + _url, withCredentials: true, + requestHeaders: {'authorization' : 'Basic $_auth'} + )).responseText; + } + + /** + * Internal method for fetching articles of blog from the server. + */ + Future _getArticles(String blog) async { + String _url = "$baseurl/rcc/api/list/?blog=$blog"; + + return (await + HttpRequest.request( + _url, withCredentials: true, + requestHeaders: {'authorization' : 'Basic $_auth'} + )).responseText; + } + + Future _getArticle(blog, post) async { + print("Blog: $blog"); + print("Post: $post"); + String _url = "$baseurl/rcc/api/post/?blog=$blog&post=$post.md"; + print("URL: $_url"); + return (await + HttpRequest.request(_url, withCredentials: true, + requestHeaders: {'authorization' : 'Basic $_auth'} + )).responseText; + } + +} diff --git a/web/article-view.dart b/web/article-view.dart new file mode 100644 index 0000000..ae632c5 --- /dev/null +++ b/web/article-view.dart @@ -0,0 +1,18 @@ +@HtmlImport('article_view.html') +library mmk2410_rangitaki_app.article_view; + +import 'package:polymer/polymer.dart'; +import 'package:web_components/web_components.dart' show HtmlImport; + +@PolymerRegister('article-view') +class ArticleView extends PolymerElement { + + ArticleView.created() : super.created(); + + @property + String title; + String author; + String date; + String text; + String tags; +} diff --git a/web/article_view.html b/web/article_view.html new file mode 100644 index 0000000..09df542 --- /dev/null +++ b/web/article_view.html @@ -0,0 +1,16 @@ + + + + diff --git a/web/index.dart b/web/index.dart new file mode 100644 index 0000000..48c08f2 --- /dev/null +++ b/web/index.dart @@ -0,0 +1,61 @@ +/** + * @author Marcel Kapfer (mmk2410) + * Library for easily working with the Rangitaki API in your browswer. + */ +library mmk2410_rangitaki_app.index; + +import 'dart:html'; +import 'dart:async'; + +import 'package:polymer/polymer.dart'; + +import 'api.dart'; +import 'article-view.dart'; + +export 'article-view.dart'; +export 'package:polymer/init.dart'; + +final String username = ""; +final String pwd = ""; +final String baseurl = ""; + +RangitakiConnect rcc; +Element itemList; +ArticleView articleView; +String currentBlog; + +main() async { + await initPolymer(); + + print("Starting..."); + + rcc = new RangitakiConnect(baseurl, username, pwd); + + await rcc.addBlogs(); + + itemList = querySelector("#main-list"); + + for (Element item in itemList.children) { + item.onClick.listen(blogSelected); + } + + articleView = querySelector("articlev-iew"); +} + +Future blogSelected(Event e) async { + Element element = e.target; + itemList.children.clear(); + currentBlog = element.id; + await rcc.addArticles(element.id); + + for (Element item in itemList.children) { + item.onClick.listen(articleSelected); + } +} + +Future articleSelected(Event e) async { + Element element = e.target; + await rcc.showArticle(currentBlog, element.id, articleView); + itemList.hidden = true; + articleView.hidden = false; +} diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..d78dcc2 --- /dev/null +++ b/web/index.html @@ -0,0 +1,57 @@ + + + + + Rangitaki + + + + + + + + + + + + + + + + + Menu + + + + Blogs + Articles + Media + Settings + + + + + + +
Rangitaki
+
+ + +
+
+ + + +
+
+ + + + + + + + diff --git a/web/main.js b/web/main.js new file mode 100644 index 0000000..02b49d7 --- /dev/null +++ b/web/main.js @@ -0,0 +1,53 @@ +const electron = require('electron'); +// Module to control application life. +const app = electron.app; +// Module to create native browser window. +const BrowserWindow = electron.BrowserWindow; + +// Keep a global reference of the window object, if you don't, the window will +// be closed automatically when the JavaScript object is garbage collected. +let mainWindow; + +function createWindow () { + // Create the browser window. + mainWindow = new BrowserWindow({width: 1000, height: 800}); + + // and load the index.html of the app. + mainWindow.loadURL(`file://${__dirname}/index.html`); + + // Open the DevTools. + mainWindow.webContents.openDevTools(); + + // Emitted when the window is closed. + mainWindow.on('closed', function () { + // Dereference the window object, usually you would store windows + // in an array if your app supports multi windows, this is the time + // when you should delete the corresponding element. + mainWindow = null; + }); +} + +// This method will be called when Electron has finished +// initialization and is ready to create browser windows. +// Some APIs can only be used after this event occurs. +app.on('ready', createWindow); + +// Quit when all windows are closed. +app.on('window-all-closed', function () { + // On OS X it is common for applications and their menu bar + // to stay active until the user quits explicitly with Cmd + Q + if (process.platform !== 'darwin') { + app.quit(); + } +}); + +app.on('activate', function () { + // On OS X it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (mainWindow === null) { + createWindow(); + } +}); + +// In this file you can include the rest of your app's specific main process +// code. You can also put them in separate files and require them here. diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..9695fbc --- /dev/null +++ b/web/package.json @@ -0,0 +1,23 @@ +{ + "name": "rangitaki-desktop", + "version": "0.0.1", + "description": "Rangtaki desktop app made with Dart, Polymer and Electron", + "main": "main.js", + "scripts": { + "start": "electron main.js" + }, + "repository": { + "type": "git", + "url": "git+https://gitlab.com/mmk2410/rangitaki-desktop.git" + }, + "keywords": [ + "Rangitaki", + "desktop" + ], + "author": "Marcel Kapfer (mmk2410)", + "license": "MIT", + "homepage": "https://gitlab.com/mmk2410/rangitaki-desktop", + "devDependencies": { + "electron-prebuilt": "^1.0.1" + } +} diff --git a/web/renderer.js b/web/renderer.js new file mode 100644 index 0000000..901d75e --- /dev/null +++ b/web/renderer.js @@ -0,0 +1,3 @@ +// This file is required by the index.html file and will +// be executed in the renderer process for that window. +// All of the Node.js APIs are available in this process. diff --git a/web/style.html b/web/style.html new file mode 100644 index 0000000..dec4d0c --- /dev/null +++ b/web/style.html @@ -0,0 +1,27 @@ + \ No newline at end of file