Initial commit

This commit is contained in:
Toby Zerner 2015-09-16 16:00:08 +09:30
commit 825b496364
26 changed files with 599 additions and 0 deletions

View File

@ -0,0 +1,19 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2
[*.{diff,md}]
trim_trailing_whitespace = false
[*.php]
indent_size = 4

View File

@ -0,0 +1,5 @@
**/bower_components/**/*
**/node_modules/**/*
vendor/**/*
**/Gulpfile.js
**/dist/**/*

175
extensions/embed/.eslintrc Normal file
View File

@ -0,0 +1,175 @@
{
"parser": "babel-eslint", // https://github.com/babel/babel-eslint
"env": { // http://eslint.org/docs/user-guide/configuring.html#specifying-environments
"browser": true // browser global variables
},
"ecmaFeatures": {
"arrowFunctions": true,
"blockBindings": true,
"classes": true,
"defaultParams": true,
"destructuring": true,
"forOf": true,
"generators": false,
"modules": true,
"objectLiteralComputedProperties": true,
"objectLiteralDuplicateProperties": false,
"objectLiteralShorthandMethods": true,
"objectLiteralShorthandProperties": true,
"spread": true,
"superInFunctions": true,
"templateStrings": true,
"jsx": true
},
"globals": {
"m": true,
"app": true,
"$": true,
"moment": true
},
"plugins": [
"react"
],
"rules": {
"react/jsx-uses-vars": 1,
/**
* Strict mode
*/
// babel inserts "use strict"; for us
"strict": [2, "never"], // http://eslint.org/docs/rules/strict
/**
* ES6
*/
"no-var": 2, // http://eslint.org/docs/rules/no-var
"prefer-const": 2, // http://eslint.org/docs/rules/prefer-const
/**
* Variables
*/
"no-shadow": 2, // http://eslint.org/docs/rules/no-shadow
"no-shadow-restricted-names": 2, // http://eslint.org/docs/rules/no-shadow-restricted-names
"no-unused-vars": [2, { // http://eslint.org/docs/rules/no-unused-vars
"vars": "local",
"args": "after-used"
}],
"no-use-before-define": 2, // http://eslint.org/docs/rules/no-use-before-define
/**
* Possible errors
*/
"comma-dangle": [2, "never"], // http://eslint.org/docs/rules/comma-dangle
"no-cond-assign": [2, "always"], // http://eslint.org/docs/rules/no-cond-assign
"no-console": 1, // http://eslint.org/docs/rules/no-console
"no-debugger": 1, // http://eslint.org/docs/rules/no-debugger
"no-alert": 1, // http://eslint.org/docs/rules/no-alert
"no-constant-condition": 1, // http://eslint.org/docs/rules/no-constant-condition
"no-dupe-keys": 2, // http://eslint.org/docs/rules/no-dupe-keys
"no-duplicate-case": 2, // http://eslint.org/docs/rules/no-duplicate-case
"no-empty": 2, // http://eslint.org/docs/rules/no-empty
"no-ex-assign": 2, // http://eslint.org/docs/rules/no-ex-assign
"no-extra-boolean-cast": 0, // http://eslint.org/docs/rules/no-extra-boolean-cast
"no-extra-semi": 2, // http://eslint.org/docs/rules/no-extra-semi
"no-func-assign": 2, // http://eslint.org/docs/rules/no-func-assign
"no-inner-declarations": 2, // http://eslint.org/docs/rules/no-inner-declarations
"no-invalid-regexp": 2, // http://eslint.org/docs/rules/no-invalid-regexp
"no-irregular-whitespace": 2, // http://eslint.org/docs/rules/no-irregular-whitespace
"no-obj-calls": 2, // http://eslint.org/docs/rules/no-obj-calls
"no-reserved-keys": 2, // http://eslint.org/docs/rules/no-reserved-keys
"no-sparse-arrays": 2, // http://eslint.org/docs/rules/no-sparse-arrays
"no-unreachable": 2, // http://eslint.org/docs/rules/no-unreachable
"use-isnan": 2, // http://eslint.org/docs/rules/use-isnan
"block-scoped-var": 2, // http://eslint.org/docs/rules/block-scoped-var
/**
* Best practices
*/
"consistent-return": 2, // http://eslint.org/docs/rules/consistent-return
"curly": [2, "multi-line"], // http://eslint.org/docs/rules/curly
"default-case": 2, // http://eslint.org/docs/rules/default-case
"dot-notation": [2, { // http://eslint.org/docs/rules/dot-notation
"allowKeywords": true
}],
"eqeqeq": 2, // http://eslint.org/docs/rules/eqeqeq
"no-caller": 2, // http://eslint.org/docs/rules/no-caller
"no-else-return": 2, // http://eslint.org/docs/rules/no-else-return
"no-eq-null": 2, // http://eslint.org/docs/rules/no-eq-null
"no-eval": 2, // http://eslint.org/docs/rules/no-eval
"no-extend-native": 2, // http://eslint.org/docs/rules/no-extend-native
"no-extra-bind": 2, // http://eslint.org/docs/rules/no-extra-bind
"no-fallthrough": 2, // http://eslint.org/docs/rules/no-fallthrough
"no-floating-decimal": 2, // http://eslint.org/docs/rules/no-floating-decimal
"no-implied-eval": 2, // http://eslint.org/docs/rules/no-implied-eval
"no-lone-blocks": 2, // http://eslint.org/docs/rules/no-lone-blocks
"no-loop-func": 2, // http://eslint.org/docs/rules/no-loop-func
"no-multi-str": 2, // http://eslint.org/docs/rules/no-multi-str
"no-native-reassign": 2, // http://eslint.org/docs/rules/no-native-reassign
"no-new": 2, // http://eslint.org/docs/rules/no-new
"no-new-func": 2, // http://eslint.org/docs/rules/no-new-func
"no-new-wrappers": 2, // http://eslint.org/docs/rules/no-new-wrappers
"no-octal": 2, // http://eslint.org/docs/rules/no-octal
"no-octal-escape": 2, // http://eslint.org/docs/rules/no-octal-escape
"no-param-reassign": 2, // http://eslint.org/docs/rules/no-param-reassign
"no-proto": 2, // http://eslint.org/docs/rules/no-proto
"no-redeclare": 2, // http://eslint.org/docs/rules/no-redeclare
"no-return-assign": 2, // http://eslint.org/docs/rules/no-return-assign
"no-self-compare": 2, // http://eslint.org/docs/rules/no-self-compare
"no-sequences": 2, // http://eslint.org/docs/rules/no-sequences
"no-throw-literal": 2, // http://eslint.org/docs/rules/no-throw-literal
"no-with": 2, // http://eslint.org/docs/rules/no-with
"radix": 2, // http://eslint.org/docs/rules/radix
"vars-on-top": 2, // http://eslint.org/docs/rules/vars-on-top
"wrap-iife": [2, "any"], // http://eslint.org/docs/rules/wrap-iife
"yoda": 2, // http://eslint.org/docs/rules/yoda
/**
* Style
*/
"indent": [2, 2], // http://eslint.org/docs/rules/indent
"brace-style": [2, // http://eslint.org/docs/rules/brace-style
"1tbs", {
"allowSingleLine": true
}],
"quotes": [
2, "single", "avoid-escape" // http://eslint.org/docs/rules/quotes
],
"camelcase": [2, { // http://eslint.org/docs/rules/camelcase
"properties": "never"
}],
"comma-spacing": [2, { // http://eslint.org/docs/rules/comma-spacing
"before": false,
"after": true
}],
"comma-style": [2, "last"], // http://eslint.org/docs/rules/comma-style
"eol-last": 2, // http://eslint.org/docs/rules/eol-last
"key-spacing": [2, { // http://eslint.org/docs/rules/key-spacing
"beforeColon": false,
"afterColon": true
}],
"new-cap": [2, { // http://eslint.org/docs/rules/new-cap
"newIsCap": true
}],
"no-multiple-empty-lines": [2, { // http://eslint.org/docs/rules/no-multiple-empty-lines
"max": 2
}],
"no-new-object": 2, // http://eslint.org/docs/rules/no-new-object
"no-spaced-func": 2, // http://eslint.org/docs/rules/no-spaced-func
"no-trailing-spaces": 2, // http://eslint.org/docs/rules/no-trailing-spaces
"no-wrap-func": 2, // http://eslint.org/docs/rules/no-wrap-func
"no-underscore-dangle": 0, // http://eslint.org/docs/rules/no-underscore-dangle
"one-var": [2, "never"], // http://eslint.org/docs/rules/one-var
"padded-blocks": [2, "never"], // http://eslint.org/docs/rules/padded-blocks
"semi": [2, "always"], // http://eslint.org/docs/rules/semi
"semi-spacing": [2, { // http://eslint.org/docs/rules/semi-spacing
"before": false,
"after": true
}],
"space-after-keywords": 2, // http://eslint.org/docs/rules/space-after-keywords
"space-before-blocks": 2, // http://eslint.org/docs/rules/space-before-blocks
"space-before-function-paren": [2, "never"], // http://eslint.org/docs/rules/space-before-function-paren
"space-infix-ops": 2, // http://eslint.org/docs/rules/space-infix-ops
"space-return-throw-case": 2, // http://eslint.org/docs/rules/space-return-throw-case
"spaced-line-comment": 2, // http://eslint.org/docs/rules/spaced-line-comment
}
}

3
extensions/embed/.gitattributes vendored Normal file
View File

@ -0,0 +1,3 @@
.gitattributes export-ignore
.gitignore export-ignore
.travis.yml export-ignore

4
extensions/embed/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/vendor
composer.phar
.DS_Store
Thumbs.db

26
extensions/embed/.php_cs Executable file
View File

@ -0,0 +1,26 @@
<?php
$header = <<<EOF
This file is part of Flarum.
(c) Toby Zerner <toby.zerner@gmail.com>
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
EOF;
Symfony\CS\Fixer\Contrib\HeaderCommentFixer::setHeader($header);
$finder = Symfony\CS\Finder\DefaultFinder::create()
->exclude('js')
->exclude('less')
->in(__DIR__);
return Symfony\CS\Config\Config::create()
->level(Symfony\CS\FixerInterface::PSR2_LEVEL)
->fixers([
'short_array_syntax',
'header_comment',
'-psr0'
])
->finder($finder);

View File

@ -0,0 +1,23 @@
language: php
php:
- 5.5
- 5.6
matrix:
allow_failures:
- php: hhvm
fast_finish: true
before_script:
- curl -s http://getcomposer.org/installer | php
- php composer.phar install
script:
- php composer.phar style
notifications:
email:
on_failure: change
sudo: false

View File

@ -0,0 +1,5 @@
<?php
require __DIR__.'/vendor/autoload.php';
return 'Flarum\Embed\Extension';

View File

@ -0,0 +1,7 @@
{
"autoload": {
"psr-4": {
"Flarum\\Embed\\": "src/"
}
}
}

View File

@ -0,0 +1,21 @@
{
"name": "embed",
"title": "Embed",
"description": "Embed Flarum discussions as comments for your blog.",
"keywords": [],
"version": "0.1.0-beta.2",
"author": {
"name": "Toby Zerner",
"email": "toby@flarum.org",
"homepage": "http://tobyzerner.com"
},
"license": "MIT",
"require": {
"flarum": ">0.1.0-beta.2"
},
"icon": {
"name": "code",
"backgroundColor": "#D0E800",
"color": "#fff"
}
}

3
extensions/embed/js/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
bower_components
node_modules
dist

View File

@ -0,0 +1,7 @@
var gulp = require('flarum-gulp');
gulp({
modules: {
'embed': 'src/**/*.js'
}
});

View File

@ -0,0 +1,7 @@
{
"private": true,
"devDependencies": {
"gulp": "^3.8.11",
"flarum-gulp": "^0.1.0"
}
}

View File

@ -0,0 +1,5 @@
import app from 'flarum/app';
app.initializers.add('embed', () => {
});

View File

@ -0,0 +1,7 @@
var gulp = require('flarum-gulp');
gulp({
modules: {
'embed': 'src/**/*.js'
}
});

View File

@ -0,0 +1,7 @@
{
"private": true,
"devDependencies": {
"gulp": "^3.8.11",
"flarum-gulp": "^0.1.0"
}
}

View File

@ -0,0 +1,40 @@
import Component from 'flarum/Component';
import PostStream from 'flarum/components/PostStream';
export default class DiscussionPage extends Component {
constructor(...args) {
super(...args);
/**
* The discussion that is being viewed.
*
* @type {Discussion}
*/
const discussion = this.discussion = app.preloadedDocument();
let includedPosts = [];
if (discussion.payload && discussion.payload.included) {
includedPosts = discussion.payload.included
.filter(record => record.type === 'posts' && record.relationships && record.relationships.discussion)
.map(record => app.store.getById('posts', record.id))
.sort((a, b) => a.id() - b.id())
.slice(0, 20);
}
this.stream = new PostStream({discussion, includedPosts});
}
view() {
return (
<div className="DiscussionPage">
<div class="container">
<div className="DiscussionPage-discussion">
<div className="DiscussionPage-stream">
{this.stream.render()}
</div>
</div>
</div>
</div>
);
}
}

View File

@ -0,0 +1,28 @@
import { override } from 'flarum/extend';
import app from 'flarum/app';
import Composer from 'flarum/components/Composer';
import ModalManager from 'flarum/components/ModalManager';
import AlertManager from 'flarum/components/AlertManager';
import DiscussionPage from 'embed/components/DiscussionPage';
app.initializers.add('boot', () => {
override(m, 'route', function(original, root, arg1, arg2, vdom) {
if (root.addEventListener || root.attachEvent) {
root.href = vdom.attrs.href;
root.target = '_blank';
// TODO: If href leads to a post within this discussion that we have
// already loaded, then scroll to it?
return;
}
original.apply(this, arguments);
});
app.composer = m.mount(document.getElementById('composer'), Composer.component());
app.modal = m.mount(document.getElementById('modal'), ModalManager.component());
app.alerts = m.mount(document.getElementById('alerts'), AlertManager.component());
m.mount(document.getElementById('content'), DiscussionPage.component());
});

View File

@ -0,0 +1,21 @@
.container {
width: auto;
padding: 0 20px;
}
.App {
padding-top: 0;
min-height: 0;
&:before {
display: none;
}
}
.App-content {
border-top: 0;
}
.DiscussionPage-stream {
margin-right: 0;
}
.Post-stream {
margin-top: 0;
}

View File

@ -0,0 +1,2 @@
embed:
# hello_world: "Hello, world!"

View File

@ -0,0 +1,44 @@
#!/usr/bin/env bash
cd $(dirname $0)
base="${PWD}/.."
cd $base
if [ ! -f flarum.json ]; then
echo "Could not find flarum.json file!"
exit 1
fi
extension=$(php <<CODE
<?php
\$flarum = json_decode(file_get_contents('flarum.json'), true);
echo array_key_exists('name', \$flarum) ? \$flarum['name'] : '';
CODE
)
release=/tmp/${extension}
rm -rf ${release}
mkdir ${release}
git archive --format zip --worktree-attributes HEAD > ${release}/release.zip
cd ${release}
unzip release.zip -d ./
rm release.zip
bash "${base}/scripts/compile.sh"
wait
# Delete files
rm -rf ${release}/scripts
rm -rf `find . -type d -name node_modules`
rm -rf `find . -type d -name bower_components`
# Finally, create the release archive
cd ${release}
find . -type d -exec chmod 0750 {} +
find . -type f -exec chmod 0644 {} +
chmod 0775 .
zip -r ${extension}.zip ./
mv ${extension}.zip ${base}/${extension}.zip

View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
base=$PWD
cd $base
composer install --prefer-dist --optimize-autoloader --ignore-platform-reqs --no-dev
cd "${base}/js/forum"
npm install
gulp --production
cd "${base}/js/admin"
npm install
gulp --production

View File

@ -0,0 +1,46 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Embed;
use Flarum\Forum\Actions\DiscussionAction as DiscussionAction;
use Psr\Http\Message\ServerRequestInterface as Request;
class ClientAction extends DiscussionAction
{
/**
* {@inheritdoc}
*
* @return ClientView
*/
public function render(Request $request, array $routeParams = [])
{
$view = parent::render($request, $routeParams);
$view->addBootstrapper('embed/main');
$view->setLayout(__DIR__.'/../views/embed.blade.php');
return $view;
}
/**
* @inheritdoc
*/
protected function getAssets()
{
$assets = parent::getAssets();
$assets->addFile(__DIR__.'/../js/forum/dist/extension.js');
$assets->addFile(__DIR__.'/../less/forum/extension.less');
$assets->setFilename('embed');
return $assets;
}
}

View File

@ -0,0 +1,12 @@
<?php namespace Flarum\Embed;
use Flarum\Support\Extension as BaseExtension;
use Illuminate\Events\Dispatcher;
class Extension extends BaseExtension
{
public function listen(Dispatcher $events)
{
$events->subscribe('Flarum\Embed\Listeners\AddClientAssets');
}
}

View File

@ -0,0 +1,31 @@
<?php namespace Flarum\Embed\Listeners;
use Flarum\Events\RegisterLocales;
use Flarum\Events\BuildClientView;
use Flarum\Events\RegisterForumRoutes;
use Illuminate\Contracts\Events\Dispatcher;
class AddClientAssets
{
public function subscribe(Dispatcher $events)
{
$events->listen(RegisterLocales::class, [$this, 'addLocale']);
$events->listen(BuildClientView::class, [$this, 'addAssets']);
$events->listen(RegisterForumRoutes::class, [$this, 'addEmbedRoute']);
}
public function addLocale(RegisterLocales $event)
{
$event->addTranslations('en', __DIR__.'/../../locale/en.yml');
}
public function addAssets(BuildClientView $event)
{
}
public function addEmbedRoute(RegisterForumRoutes $event)
{
$event->get('/embed/{id:\d+}', 'embed.discussion', 'Flarum\Embed\ClientAction');
}
}

View File

@ -0,0 +1,38 @@
<?php
/**
* Forum Client Template
*
* NOTE: You shouldn't edit this file directly. Your changes will be overwritten
* when you update Flarum. See flarum.org/docs/templates to learn how to
* customize your forum's layout.
*
* Flarum's JavaScript client mounts various components into key elements in
* this template. They are distinguished by their ID attributes:
*
* - #app
* - #app-navigation
* - #drawer
* - #header
* - #header-navigation
* - #home-link
* - #header-primary
* - #header-secondary
* - #content
* - #composer
*/
?>
<div id="app" class="App">
<main class="App-content">
<div id="content"></div>
{!! $content !!}
<div class="App-composer">
<div class="container">
<div id="composer"></div>
</div>
</div>
</main>
</div>