move everything
This commit is contained in:
parent
efb14f90e1
commit
cd5b93eb0c
45 changed files with 195 additions and 686 deletions
6
.babelrc
6
.babelrc
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"presets": [
|
||||
"es2015",
|
||||
"stage-0"
|
||||
]
|
||||
}
|
19
.eslintrc
19
.eslintrc
|
@ -1,19 +0,0 @@
|
|||
{
|
||||
"ecmaFeatures": {
|
||||
"jsx": true,
|
||||
"modules": true
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
"rules": {
|
||||
// "quotes": [2, "single"],
|
||||
"jsx-quotes": 2,
|
||||
"strict": [
|
||||
2,
|
||||
"never"
|
||||
]
|
||||
}
|
||||
}
|
53
Vagrantfile
vendored
53
Vagrantfile
vendored
|
@ -1,53 +0,0 @@
|
|||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
VAGRANTFILE_API_VERSION = "2"
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
|
||||
config.vm.box = "avenuefactory/lamp"
|
||||
config.vm.network "forwarded_port", guest: 80, host: 8080
|
||||
config.vm.network "forwarded_port", guest: 993, host: 9993
|
||||
|
||||
config.vm.synced_folder "./", "/var/www/html", id: "vagrant-root",
|
||||
owner: "vagrant",
|
||||
group: "www-data",
|
||||
mount_options: ["dmode=775,fmode=664"]
|
||||
|
||||
config.vm.provision "shell", inline: <<-SHELL
|
||||
echo updating... && sudo apt-get -qq update
|
||||
echo installing... && sudo apt-get -qq -y install php5-imap
|
||||
sudo service apache2 restart
|
||||
|
||||
# Install and Configure Dovecot (http://blog.tedivm.com/open-source/2014/03/building-an-email-library-testing-with-vagrant-dovecot-and-travis-ci/)
|
||||
#https://github.com/tedious/DovecotTesting/blob/master/resources/Scripts/Provision.sh
|
||||
if which dovecot > /dev/null; then
|
||||
echo 'Dovecot is already installed'
|
||||
else
|
||||
|
||||
sudo mkdir /home/vagrant/Maildir
|
||||
sudo chown -R vagrant:vagrant /home/vagrant/Maildir
|
||||
sudo chmod a+rw /home/vagrant/Maildir
|
||||
|
||||
echo 'Installing Dovecot'
|
||||
sudo apt-get -qq -y install dovecot-imapd
|
||||
sudo touch /etc/dovecot/local.conf
|
||||
sudo chmod go+rw /etc/dovecot/local.conf
|
||||
echo 'mail_location = maildir:/home/vagrant/Maildir' >> /etc/dovecot/local.conf
|
||||
echo 'disable_plaintext_auth = no' >> /etc/dovecot/local.conf
|
||||
echo 'mail_max_userip_connections = 10000' >> /etc/dovecot/local.conf
|
||||
sudo restart dovecot
|
||||
fi
|
||||
|
||||
# Create user "test"
|
||||
if getent passwd test > /dev/null; then
|
||||
echo 'test already exists'
|
||||
else
|
||||
sudo useradd "test" -m -s /bin/bash
|
||||
echo "test:test"|sudo chpasswd
|
||||
echo 'User "test" created'
|
||||
fi
|
||||
|
||||
SHELL
|
||||
|
||||
|
||||
end
|
5
build.sh
5
build.sh
|
@ -6,10 +6,5 @@ composer install
|
|||
# copy backend
|
||||
cp -rv src/{backend.php,config.sample.php} dist/
|
||||
|
||||
# install javascript dependencies
|
||||
npm install
|
||||
|
||||
# build Javascript frontend
|
||||
npm run build
|
||||
|
||||
echo "done"
|
|
@ -3,6 +3,6 @@
|
|||
"php-imap/php-imap": "~2.0"
|
||||
},
|
||||
"config": {
|
||||
"vendor-dir": "dist/backend-libs"
|
||||
"vendor-dir": "src/backend-libs"
|
||||
}
|
||||
}
|
||||
|
|
114
dist/backend.php
vendored
114
dist/backend.php
vendored
|
@ -1,114 +0,0 @@
|
|||
<?php
|
||||
# set the new path of config.php (must be in a safe location outside the `public_html`)
|
||||
require_once '../../config.php';
|
||||
|
||||
# load php dependencies:
|
||||
require_once './backend-libs/autoload.php';
|
||||
|
||||
$imap_settings = $config['imap'];
|
||||
$mailbox = new PhpImap\Mailbox($imap_settings['url'], $imap_settings['username'], $imap_settings['password']);
|
||||
|
||||
/**
|
||||
* print error and stop program.
|
||||
* @param $status http status
|
||||
* @param $text error text
|
||||
*/
|
||||
function error($status, $text) {
|
||||
@http_response_code($status);
|
||||
@print("{\"error\": \"$text\"}");
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* print all mails for the given $user as a json string.
|
||||
* @param $username
|
||||
*/
|
||||
function print_inbox($username) {
|
||||
global $mailbox, $config;
|
||||
|
||||
$name = clean_name($username);
|
||||
if (strlen($name) === 0) {
|
||||
error(400, 'invalid username');
|
||||
}
|
||||
$to = get_address($name, $config['mailHostname']);
|
||||
$mail_ids = search_mails($to, $mailbox);
|
||||
|
||||
$emails = array();
|
||||
foreach ($mail_ids as $id) {
|
||||
$emails[] = $mailbox->getMail($id);
|
||||
}
|
||||
$address = get_address($name, $config['mailHostname']);
|
||||
$data = array("mails" => $emails, 'username' => $name, 'address' => $address);
|
||||
print(json_encode($data));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search for mails with the recipient $to.
|
||||
* @return array mail ids
|
||||
*/
|
||||
function search_mails($to, $mailbox) {
|
||||
$filterTO = 'TO "' . $to . '"';
|
||||
$filterCC = 'CC "' . $to . '"';
|
||||
$mailsIdsTo = imap_sort($mailbox->getImapStream(), SORTARRIVAL, true, SE_UID, $filterTO);
|
||||
$mailsIdsCc = imap_sort($mailbox->getImapStream(), SORTARRIVAL, true, SE_UID, $filterCC);
|
||||
return array_merge($mailsIdsTo, $mailsIdsCc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove illegal characters from username and remove everything after the @-sign. You may extend it if your server supports them.
|
||||
* @param $username
|
||||
* @return clean username
|
||||
*/
|
||||
function clean_name($username) {
|
||||
$username = preg_replace('/@.*$/', "", $username); // remove part after @
|
||||
$username = preg_replace('/[^A-Za-z0-9_.+-]/', "", $username); // remove special characters
|
||||
return $username;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates the full email address
|
||||
* @param $username
|
||||
* @param $domain
|
||||
* @return $username@$domain
|
||||
*/
|
||||
function get_address($username, $domain) {
|
||||
return $username . "@" . $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes messages older than X days.
|
||||
*/
|
||||
function delete_old_messages() {
|
||||
global $mailbox;
|
||||
|
||||
$date = date('d-M-Y', strtotime('30 days ago'));
|
||||
$ids = $mailbox->searchMailbox('BEFORE ' . $date);
|
||||
foreach ($ids as $id) {
|
||||
$mailbox->deleteMail($id);
|
||||
}
|
||||
$mailbox->expungeDeletedMails();
|
||||
}
|
||||
|
||||
|
||||
header('Content-type: application/json');
|
||||
|
||||
// Never cache requests:
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
|
||||
if (!isset($_GET['action'])) {
|
||||
error(400, 'invalid parameter');
|
||||
}
|
||||
$action = $_GET['action'];
|
||||
|
||||
if ($action === "get" && isset($_GET['username'])) {
|
||||
print_inbox($_GET['username']);
|
||||
} else {
|
||||
error(400, 'invalid action');
|
||||
}
|
||||
|
||||
// run on every request
|
||||
delete_old_messages();
|
58
dist/bundle_a99458ea657979e9cab2.js
vendored
58
dist/bundle_a99458ea657979e9cab2.js
vendored
File diff suppressed because one or more lines are too long
1
dist/bundle_a99458ea657979e9cab2.js.map
vendored
1
dist/bundle_a99458ea657979e9cab2.js.map
vendored
File diff suppressed because one or more lines are too long
17
dist/config.sample.php
vendored
17
dist/config.sample.php
vendored
|
@ -1,17 +0,0 @@
|
|||
<?php
|
||||
|
||||
date_default_timezone_set('Europe/Paris');
|
||||
error_reporting(0);
|
||||
|
||||
// configure this option if you want to allow requests from clients from other domains:
|
||||
// see https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
|
||||
// header("Access-Control-Allow-Origin: *");
|
||||
|
||||
// setup imap connection
|
||||
$config['imap']['host'] = "localhost";
|
||||
$config['imap']['url'] = '{' . $config['imap']['host'] . '/imap/ssl}INBOX';
|
||||
$config['imap']['username'] = "test";
|
||||
$config['imap']['password'] = "test";
|
||||
|
||||
// email domain, usually different from imap hostname:
|
||||
$config['mailHostname'] = "example.com";
|
1
dist/index.html
vendored
1
dist/index.html
vendored
|
@ -1 +0,0 @@
|
|||
<!DOCTYPE html> <html lang=de> <head> <meta charset=utf-8> <title>Mailbox</title> <meta name=viewport content="width=device-width,initial-scale=1,shrink-to-fit=no"> <meta name=mobile-web-app-capable content=yes> <meta name=apple-mobile-web-app-capable content=yes> <meta name=apple-mobile-web-app-status-bar-style content=black> <meta name=description content=Mailbox> <link rel=icon href="data:;base64,iVBORw0KGgo="> </head> <body ng-app=app ng-cloak> <app></app> <footer> <p>Powered by <a href=https://github.com/synox/disposable-mailbox><strong>synox/disposable-mailbox</strong></a> | <a href=https://github.com/synox/disposable-mailbox><span class="octicon octicon-mark-github"></span> Fork me on github</a></p> </footer> <script type="text/javascript" src="bundle_a99458ea657979e9cab2.js"></script></body> </html>
|
51
package.json
51
package.json
|
@ -1,51 +0,0 @@
|
|||
{
|
||||
"name": "disposable-mailbox",
|
||||
"version": "0.0.1",
|
||||
"description": "disposable-mailbox",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"build": "NODE_ENV=production webpack -p",
|
||||
"size": "NODE_ENV=production webpack --json | webpack-bundle-size-analyzer ",
|
||||
"lint": "./node_modules/eslint/bin/eslint.js src"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/synox/disposable-mailbox.git"
|
||||
},
|
||||
"homepage": "https://github.com/synox/disposable-mailbox",
|
||||
"dependencies": {
|
||||
"angular": "^1.5.2",
|
||||
"angular-sanitize": "^1.5.6",
|
||||
"angular-stickyfill": "^0.1.0",
|
||||
"hasher": "^1.2.0",
|
||||
"autolinker": "^0.27.0",
|
||||
"babel-polyfill": "^6.9.1",
|
||||
"bootstrap": "^4.0.0-alpha.3",
|
||||
"phonetic": "^0.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.0.20",
|
||||
"babel-eslint": "^4.1.3",
|
||||
"babel-loader": "^6.0.1",
|
||||
"babel-preset-es2015": "^6.0.15",
|
||||
"babel-preset-stage-0": "^6.0.15",
|
||||
"css-loader": "^0.23.1",
|
||||
"eslint": "^1.10.3",
|
||||
"file-loader": "^0.9.0",
|
||||
"html-loader": "^0.4.3",
|
||||
"html-webpack-plugin": "^2.15.0",
|
||||
"json-loader": "^0.5.4",
|
||||
"ng-annotate-webpack-plugin": "^0.1.3",
|
||||
"node-sass": "^3.8.0",
|
||||
"sass-loader": "^4.0.0",
|
||||
"style-loader": "^0.13.0",
|
||||
"uglify-loader": "^1.3.0",
|
||||
"url-loader": "^0.5.6",
|
||||
"webpack": "^1.12.2",
|
||||
"webpack-bundle-size-analyzer": "^2.0.2",
|
||||
"webpack-dev-server": "^1.12.1",
|
||||
"webpack-merge": "^0.14.1",
|
||||
"webpack-validator": "^2.2.3"
|
||||
},
|
||||
"license": "CC-BY-NC-SA-4.0"
|
||||
}
|
14
server.js
14
server.js
|
@ -1,14 +0,0 @@
|
|||
var webpack = require('webpack');
|
||||
var WebpackDevServer = require('webpack-dev-server');
|
||||
var config = require('./webpack.config');
|
||||
|
||||
new WebpackDevServer(webpack(config), {
|
||||
hot: false,
|
||||
historyApiFallback: true
|
||||
}).listen(3000, 'localhost', function (err, result) {
|
||||
if (err) {
|
||||
return console.log(err);
|
||||
}
|
||||
|
||||
console.log('Listening at http://localhost:3000/');
|
||||
});
|
5
src/chance.min.js
vendored
5
src/chance.min.js
vendored
File diff suppressed because one or more lines are too long
12
src/client_libs/angular-stickyfill-0.1.0/angular-stickyfill.css
Executable file
12
src/client_libs/angular-stickyfill-0.1.0/angular-stickyfill.css
Executable file
|
@ -0,0 +1,12 @@
|
|||
[ec-stickyfill] {
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
[ec-stickyfill]:before,
|
||||
[ec-stickyfill]:after {
|
||||
content: '';
|
||||
display: table;
|
||||
}
|
||||
|
8
src/client_libs/angular-stickyfill-0.1.0/angular-stickyfill.js
vendored
Executable file
8
src/client_libs/angular-stickyfill-0.1.0/angular-stickyfill.js
vendored
Executable file
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* An Angular directive for stickyfill (position sticky polyfill)
|
||||
*
|
||||
* @version v0.1.0 - 2016-08-31
|
||||
* @author Corey Wilson <corey@eastcodes.com>
|
||||
* @license Unlicense, http://unlicense.org/
|
||||
*/
|
||||
!function(e,i){"use strict";if("function"==typeof define&&define.amd)define(["angular","stickyfill"],i);else{if("undefined"==typeof module||"object"!=typeof module.exports)return i(e.angular,e.Stickyfill);module.exports=i(require("angular"),require("stickyfill"))}}(window,function(e,i){"use strict";function t(){function e(e,t,n){if("object"!=typeof i)throw new Error("stickyfill.js not loaded");i.add(t[0]),e.$on("$destroy",function(){i.remove(t[0])})}var t={link:e,restrict:"A"};return t}if("function"==typeof i)var i=i();var n="ec.stickyfill";return e.module(n,[]).directive("ecStickyfill",t),n});
|
Before Width: | Height: | Size: 262 B After Width: | Height: | Size: 262 B |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
82
src/client_libs/style.css
Normal file
82
src/client_libs/style.css
Normal file
|
@ -0,0 +1,82 @@
|
|||
|
||||
body {
|
||||
background: #eeeeee;
|
||||
}
|
||||
|
||||
footer p {
|
||||
margin-top: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.email-table {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
div.min-height {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.nav-container {
|
||||
background-color: #D9E2E9;
|
||||
}
|
||||
|
||||
.octicon-inbox {
|
||||
display: inline-block;
|
||||
width: 26px;
|
||||
height: 23px;
|
||||
background: url('octicon-inbox.gif') no-repeat;
|
||||
}
|
||||
|
||||
.sticky-header {
|
||||
top: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.email {
|
||||
border-bottom: 1px solid #7C96AB;
|
||||
}
|
||||
|
||||
.email .email-summary {
|
||||
font-weight: bold;
|
||||
border-top: 5px solid #7C96AB;
|
||||
border-bottom: 1px solid #7C96AB;
|
||||
padding: 10px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.email .email-headers {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.email .email-headers dl {
|
||||
padding: 0 0 4px;
|
||||
color: black;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.email .email-headers dl dt {
|
||||
float: left;
|
||||
color: black;
|
||||
margin: 0 3px 0 0;
|
||||
}
|
||||
|
||||
.email .email-headers dl dd {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin-bottom: .3rem;
|
||||
}
|
||||
|
||||
.email .mail-content {
|
||||
background-color: white;
|
||||
padding-left: 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.waiting-screen {
|
||||
padding: 40px 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.min-height {
|
||||
min-height: 400px;
|
||||
}
|
|
@ -9,11 +9,15 @@
|
|||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="description" content="Mailbox">
|
||||
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link rel="stylesheet" href="angular-stickyfill-0.1.0/angular-stickyfill.css">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css"
|
||||
integrity="sha384-AysaV+vQoT3kOAXZkl02PThvDr8HYKPZhNT5h/CXfBThSRXQ6jW5DO2ekP5ViFdi" crossorigin="anonymous">
|
||||
</head>
|
||||
<body><!-- ng-cloak-->
|
||||
<body>
|
||||
|
||||
|
||||
<main ng-controller="MailboxController as $ctrl">
|
||||
<div ng-controller="MailboxController as $ctrl"> <!-- ng-cloak-->
|
||||
|
||||
<div class="nav-container">
|
||||
<div class="container">
|
||||
|
@ -47,15 +51,72 @@
|
|||
</div>
|
||||
|
||||
|
||||
<!--<inbox-->
|
||||
<!--mails="$ctrl.mails"-->
|
||||
<!--username="$ctrl.username"-->
|
||||
<!--address="$ctrl.address"-->
|
||||
<!--state="$ctrl.state">-->
|
||||
<!--</inbox>-->
|
||||
<main>
|
||||
<div class="container min-height">
|
||||
<p ng-if="!$ctrl.username">
|
||||
Use the buttons above to create a new inbox, or open a specific mailbox.
|
||||
</p>
|
||||
|
||||
<div ng-if="$ctrl.username && $ctrl.mails.length == 0">
|
||||
<div class="waiting-screen">
|
||||
<h1>{{$ctrl.address}}</h1>
|
||||
<p class="lead">Inbox is empty.</p>
|
||||
<p><br/>
|
||||
<img src="spinner.gif">
|
||||
<br/></p>
|
||||
<p class="lead">Emails to {{address}} will be automatically displayed on this page. </p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="$ctrl.username" ng-repeat="mail in $ctrl.mails | orderBy:'-date' track by $index"
|
||||
class="email-table">
|
||||
|
||||
<!-- email -->
|
||||
<section class="email">
|
||||
<div class="row sticky-header" ec-stickyfill>
|
||||
<div class="col-sm-12 email-summary">{{mail.subject}}</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12 email-headers">
|
||||
<dl>
|
||||
<dt>To:</dt>
|
||||
<dd>{{mail.toString}}</dd>
|
||||
<div ng-if="mail.cc" ng-repeat="(address,name) in mail.cc">
|
||||
<dt>CC:</dt>
|
||||
<dd>{{address}}</dd>
|
||||
</div>
|
||||
<dt>From:</dt>
|
||||
<dd>{{mail.fromName}} <{{mail.fromAddress}}></dd>
|
||||
<dt>Date:</dt>
|
||||
<dd>{{mail.date}}</dd>
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mail-content" ng-init="htmlTabActive=false">
|
||||
|
||||
|
||||
</main>
|
||||
<button ng-show="htmlTabActive" class="btn btn-outline-info btn-sm"
|
||||
ng-click="htmlTabActive=false">show text
|
||||
</button>
|
||||
<button ng-show="mail.textHtml && !htmlTabActive" class="btn btn-outline-info btn-sm"
|
||||
ng-click="htmlTabActive=true">show html
|
||||
</button>
|
||||
|
||||
<div ng-if="!htmlTabActive" ng-bind-html="mail.textPlain | nl2br | autolink "></div>
|
||||
<div ng-if="htmlTabActive" class="mail-conent" ng-bind-html="mail.textHtml"></div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<footer>
|
||||
|
@ -65,7 +126,10 @@
|
|||
</footer>
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
|
||||
<script src="chance.min.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-sanitize.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/autolinker/1.2.0/Autolinker.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.0.4/chance.min.js"></script>
|
||||
<script src="angular-stickyfill-0.1.0/angular-stickyfill.js"></script>
|
||||
<script src="index.js"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/js-signals/1.0.0/js-signals.js"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/hasher/1.2.0/hasher.js"></script>
|
||||
|
|
20
src/index.js
20
src/index.js
|
@ -21,11 +21,27 @@ function cleanUsername(username) {
|
|||
}
|
||||
|
||||
|
||||
var app = angular.module('app', []);
|
||||
var app = angular.module('app', ["ngSanitize"]);
|
||||
|
||||
// http://stackoverflow.com/a/20033625/79461
|
||||
app.filter("nl2br", function () {
|
||||
return function (data) {
|
||||
if (!data) return data;
|
||||
return data.replace(/\r?\n/g, '<br/>');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// http://stackoverflow.com/a/20033625/79461
|
||||
app.filter("autolink", function () {
|
||||
return function (data) {
|
||||
return Autolinker.link(data, {truncate: {length: 50, location: 'middle', newWindow: true}});
|
||||
}
|
||||
});
|
||||
|
||||
app.controller('MailboxController', ["$scope", "$interval", "$http", "$log", function ($scope, $interval, $http, $log) {
|
||||
var self = this;
|
||||
|
||||
|
||||
self.updateUsername = function (username) {
|
||||
self.username = cleanUsername(username);
|
||||
if (self.username.length > 0) {
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
.nav-container {
|
||||
background-color: #D9E2E9;
|
||||
//heigh: 300px;
|
||||
}
|
||||
|
||||
.octicon-inbox {
|
||||
display: inline-block;
|
||||
width: 26px;
|
||||
height: 23px;
|
||||
background: url('octicon-inbox.gif') no-repeat;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
<main>
|
||||
<div class="container min-height">
|
||||
<p ng-if="!$ctrl.username">
|
||||
Use the buttons above to create a new inbox, or open a specific mailbox.
|
||||
</p>
|
||||
|
||||
<div ng-if="$ctrl.username && $ctrl.mails.length == 0">
|
||||
<div class="waiting-screen">
|
||||
<h1>{{$ctrl.address}}</h1>
|
||||
<p class="lead">Inbox is empty.</p>
|
||||
<p><br/>
|
||||
<img src="spinner.gif">
|
||||
<br/></p>
|
||||
<p class="lead">Emails to {{address}} will be automatically displayed on this page. </p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div ng-if="$ctrl.username" ng-repeat="mail in $ctrl.mails | orderBy:'-date' track by $index"
|
||||
class="email-table">
|
||||
<mail mail="mail"></mail>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
|
@ -1,29 +0,0 @@
|
|||
import angular from "angular";
|
||||
import template from "./list.html";
|
||||
import "./list.scss";
|
||||
|
||||
|
||||
class ListController {
|
||||
/*@ngInject*/
|
||||
constructor($log) {
|
||||
this.$log = $log;
|
||||
|
||||
// @Input:
|
||||
// this.mails = [];
|
||||
// this.username = null;
|
||||
// this.address = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default angular.module('mailbox.inbox', [])
|
||||
.component('inbox', {
|
||||
template, controller: ListController,
|
||||
bindings: {
|
||||
address: '<',
|
||||
username: '<',
|
||||
mails: '<',
|
||||
state: '<'
|
||||
}
|
||||
})
|
||||
.name;
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
body {
|
||||
background: #eeeeee;
|
||||
}
|
||||
|
||||
footer p {
|
||||
margin-top: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.email-table {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
div.min-height {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
<section class="email">
|
||||
<div class="row sticky-header" ec-stickyfill>
|
||||
<div class="col-sm-12 email-summary">{{$ctrl.mail.subject}}</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12 email-headers">
|
||||
<dl>
|
||||
<dt>To:</dt>
|
||||
<dd>{{$ctrl.mail.toString}}</dd>
|
||||
<div ng-if="$ctrl.mail.cc" ng-repeat="(address,name) in $ctrl.mail.cc">
|
||||
<dt>CC:</dt>
|
||||
<dd>{{address}}</dd>
|
||||
</div>
|
||||
<dt>From:</dt>
|
||||
<dd>{{$ctrl.mail.fromName}} <{{$ctrl.mail.fromAddress}}></dd>
|
||||
<dt>Date:</dt>
|
||||
<dd>{{$ctrl.mail.date}}</dd>
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mail-content" ng-init="htmlTabActive=false">
|
||||
|
||||
|
||||
<button ng-show="htmlTabActive" class="btn btn-outline-info btn-sm" ng-click="htmlTabActive=false">show text
|
||||
</button>
|
||||
<button ng-show="$ctrl.mail.textHtml && !htmlTabActive" class="btn btn-outline-info btn-sm"
|
||||
ng-click="htmlTabActive=true">show html
|
||||
</button>
|
||||
|
||||
<div ng-if="!htmlTabActive" ng-bind-html="$ctrl.mail.textPlain | nl2br | autolink "></div>
|
||||
<div ng-if="htmlTabActive" class="mail-conent" ng-bind-html="$ctrl.mail.textHtml"></div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
import angular from "angular";
|
||||
import ngSanitize from "angular-sanitize";
|
||||
import Autolinker from "autolinker";
|
||||
import angularStickyfill from "angular-stickyfill";
|
||||
import "angular-stickyfill/dist/angular-stickyfill.css";
|
||||
import template from "./mail.html";
|
||||
import "./mail.scss";
|
||||
|
||||
|
||||
class MailController {
|
||||
/*@ngInject*/
|
||||
constructor() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default angular.module('mailbox.inbox.mail', [ngSanitize, angularStickyfill])
|
||||
.component('mail', {
|
||||
template,
|
||||
controller: MailController,
|
||||
bindings: {
|
||||
mail: '<'
|
||||
}
|
||||
})
|
||||
// http://stackoverflow.com/a/20033625/79461
|
||||
.filter("nl2br", function () {
|
||||
return function (data) {
|
||||
if (!data) return data;
|
||||
return data.replace(/\r?\n/g, '<br/>');
|
||||
}
|
||||
}
|
||||
)
|
||||
// http://stackoverflow.com/a/20033625/79461
|
||||
.filter("autolink", function () {
|
||||
return function (data) {
|
||||
return Autolinker.link(data, {truncate: {length: 50, location: 'middle', newWindow: true}});
|
||||
}
|
||||
}
|
||||
).name;
|
|
@ -1,55 +0,0 @@
|
|||
$email-border-color: #7C96AB;
|
||||
$email-summary-background: white;
|
||||
$email-header-background: white;
|
||||
|
||||
.sticky-header {
|
||||
top: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.email {
|
||||
.email-summary {
|
||||
font-weight: bold;
|
||||
border-top: 5px solid $email-border-color;
|
||||
border-bottom: 1px solid $email-border-color;
|
||||
padding: 10px;
|
||||
background-color: $email-summary-background;
|
||||
}
|
||||
|
||||
.email-headers {
|
||||
background-color: $email-header-background;
|
||||
|
||||
dl {
|
||||
padding: 0 0 4px;
|
||||
color: black;
|
||||
overflow: hidden;
|
||||
|
||||
dt {
|
||||
float: left;
|
||||
color: black;
|
||||
margin: 0 3px 0 0;
|
||||
}
|
||||
dd {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin-bottom: .3rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mail-content {
|
||||
background-color: white;
|
||||
padding-left: 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.waiting-screen {
|
||||
padding: 40px 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.min-height {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
var webpack = require('webpack');
|
||||
var path = require('path');
|
||||
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
var validate = require('webpack-validator');
|
||||
var merge = require('webpack-merge');
|
||||
var ngAnnotatePlugin = require('ng-annotate-webpack-plugin');
|
||||
|
||||
var TARGET = process.env.npm_lifecycle_event;
|
||||
|
||||
// based on https://github.com/gaearon/react-hot-boilerplate
|
||||
const commonConfig = {
|
||||
context: path.resolve(__dirname, 'src'),
|
||||
entry: [
|
||||
'./index.js'
|
||||
],
|
||||
output: {
|
||||
path: path.join(__dirname, 'dist'),
|
||||
filename: 'bundle_[hash].js'
|
||||
},
|
||||
plugins: [
|
||||
new webpack.NoErrorsPlugin(),
|
||||
new HtmlWebpackPlugin({
|
||||
template: './index.html'
|
||||
}),
|
||||
new ngAnnotatePlugin({add: true})
|
||||
],
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel',
|
||||
exclude: [/node_modules/],
|
||||
include: path.join(__dirname, 'src'),
|
||||
query: {
|
||||
// https://github.com/babel/babel-loader#options
|
||||
cacheDirectory: true,
|
||||
presets: ['es2015']
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.json$/, loader: 'json'
|
||||
}, {
|
||||
test: /\.html$/, loader: 'html'
|
||||
}, {
|
||||
test: /\.css$/, loader: 'style!css'
|
||||
}, {
|
||||
test: /\.scss$/, loader: 'style!css!sass'
|
||||
}, {
|
||||
test: /\.(jpe?g|png|gif|svg)$/i, loader: 'url'
|
||||
}, {
|
||||
test: /\.(woff|woff2)$/, loader: 'url?mimetype=application/font-woff'
|
||||
}, {
|
||||
test: /\.ttf$/, loader: 'url'
|
||||
}, {
|
||||
test: /\.eot$/, loader: 'url'
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
var config;
|
||||
switch (TARGET) {
|
||||
case 'size':
|
||||
case 'build':
|
||||
config = merge(commonConfig, {
|
||||
devtool: 'source-map',
|
||||
plugins: [
|
||||
new webpack.optimize.DedupePlugin(),
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
minimize: true,
|
||||
compress: {
|
||||
warnings: false
|
||||
}
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
DEVELOPMENT: JSON.stringify(false)
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
'NODE_ENV': JSON.stringify('production')
|
||||
}
|
||||
})
|
||||
|
||||
]
|
||||
});
|
||||
break;
|
||||
default:
|
||||
// develop
|
||||
config = merge(commonConfig, {
|
||||
devtool: 'eval',
|
||||
plugins: [
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
DEVELOPMENT: JSON.stringify(true)
|
||||
})
|
||||
]
|
||||
|
||||
});
|
||||
// replace entry instead of merge
|
||||
config.entry = [
|
||||
'webpack-dev-server/client?http://localhost:3000',
|
||||
'webpack/hot/only-dev-server',
|
||||
'./index.js'
|
||||
];
|
||||
}
|
||||
|
||||
if (TARGET === "size") {
|
||||
// no validation with size target
|
||||
module.exports = config;
|
||||
} else {
|
||||
module.exports = validate(config);
|
||||
}
|
||||
|
Loading…
Reference in a new issue