From 825b4963644c926cb0c6f877777b064b1ad82206 Mon Sep 17 00:00:00 2001 From: Toby Zerner Date: Wed, 16 Sep 2015 16:00:08 +0930 Subject: [PATCH] Initial commit --- extensions/embed/.editorconfig | 19 ++ extensions/embed/.eslintignore | 5 + extensions/embed/.eslintrc | 175 ++++++++++++++++++ extensions/embed/.gitattributes | 3 + extensions/embed/.gitignore | 4 + extensions/embed/.php_cs | 26 +++ extensions/embed/.travis.yml | 23 +++ extensions/embed/bootstrap.php | 5 + extensions/embed/composer.json | 7 + extensions/embed/flarum.json | 21 +++ extensions/embed/js/.gitignore | 3 + extensions/embed/js/admin/Gulpfile.js | 7 + extensions/embed/js/admin/package.json | 7 + extensions/embed/js/admin/src/main.js | 5 + extensions/embed/js/forum/Gulpfile.js | 7 + extensions/embed/js/forum/package.json | 7 + .../js/forum/src/components/DiscussionPage.js | 40 ++++ extensions/embed/js/forum/src/main.js | 28 +++ extensions/embed/less/forum/extension.less | 21 +++ extensions/embed/locale/en.yml | 2 + extensions/embed/scripts/build.sh | 44 +++++ extensions/embed/scripts/compile.sh | 13 ++ extensions/embed/src/ClientAction.php | 46 +++++ extensions/embed/src/Extension.php | 12 ++ .../embed/src/Listeners/AddClientAssets.php | 31 ++++ extensions/embed/views/embed.blade.php | 38 ++++ 26 files changed, 599 insertions(+) create mode 100644 extensions/embed/.editorconfig create mode 100644 extensions/embed/.eslintignore create mode 100644 extensions/embed/.eslintrc create mode 100644 extensions/embed/.gitattributes create mode 100644 extensions/embed/.gitignore create mode 100755 extensions/embed/.php_cs create mode 100644 extensions/embed/.travis.yml create mode 100644 extensions/embed/bootstrap.php create mode 100644 extensions/embed/composer.json create mode 100644 extensions/embed/flarum.json create mode 100644 extensions/embed/js/.gitignore create mode 100644 extensions/embed/js/admin/Gulpfile.js create mode 100644 extensions/embed/js/admin/package.json create mode 100644 extensions/embed/js/admin/src/main.js create mode 100644 extensions/embed/js/forum/Gulpfile.js create mode 100644 extensions/embed/js/forum/package.json create mode 100644 extensions/embed/js/forum/src/components/DiscussionPage.js create mode 100644 extensions/embed/js/forum/src/main.js create mode 100644 extensions/embed/less/forum/extension.less create mode 100644 extensions/embed/locale/en.yml create mode 100755 extensions/embed/scripts/build.sh create mode 100755 extensions/embed/scripts/compile.sh create mode 100644 extensions/embed/src/ClientAction.php create mode 100644 extensions/embed/src/Extension.php create mode 100644 extensions/embed/src/Listeners/AddClientAssets.php create mode 100644 extensions/embed/views/embed.blade.php diff --git a/extensions/embed/.editorconfig b/extensions/embed/.editorconfig new file mode 100644 index 000000000..87694ddab --- /dev/null +++ b/extensions/embed/.editorconfig @@ -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 diff --git a/extensions/embed/.eslintignore b/extensions/embed/.eslintignore new file mode 100644 index 000000000..86b7c8854 --- /dev/null +++ b/extensions/embed/.eslintignore @@ -0,0 +1,5 @@ +**/bower_components/**/* +**/node_modules/**/* +vendor/**/* +**/Gulpfile.js +**/dist/**/* diff --git a/extensions/embed/.eslintrc b/extensions/embed/.eslintrc new file mode 100644 index 000000000..9e89e6ba6 --- /dev/null +++ b/extensions/embed/.eslintrc @@ -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 + } +} diff --git a/extensions/embed/.gitattributes b/extensions/embed/.gitattributes new file mode 100644 index 000000000..4afe79241 --- /dev/null +++ b/extensions/embed/.gitattributes @@ -0,0 +1,3 @@ +.gitattributes export-ignore +.gitignore export-ignore +.travis.yml export-ignore diff --git a/extensions/embed/.gitignore b/extensions/embed/.gitignore new file mode 100644 index 000000000..a4f3b125e --- /dev/null +++ b/extensions/embed/.gitignore @@ -0,0 +1,4 @@ +/vendor +composer.phar +.DS_Store +Thumbs.db diff --git a/extensions/embed/.php_cs b/extensions/embed/.php_cs new file mode 100755 index 000000000..20d29c766 --- /dev/null +++ b/extensions/embed/.php_cs @@ -0,0 +1,26 @@ + + +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); diff --git a/extensions/embed/.travis.yml b/extensions/embed/.travis.yml new file mode 100644 index 000000000..692e09f86 --- /dev/null +++ b/extensions/embed/.travis.yml @@ -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 diff --git a/extensions/embed/bootstrap.php b/extensions/embed/bootstrap.php new file mode 100644 index 000000000..b3a3fa84b --- /dev/null +++ b/extensions/embed/bootstrap.php @@ -0,0 +1,5 @@ +0.1.0-beta.2" + }, + "icon": { + "name": "code", + "backgroundColor": "#D0E800", + "color": "#fff" + } +} diff --git a/extensions/embed/js/.gitignore b/extensions/embed/js/.gitignore new file mode 100644 index 000000000..372e20a51 --- /dev/null +++ b/extensions/embed/js/.gitignore @@ -0,0 +1,3 @@ +bower_components +node_modules +dist diff --git a/extensions/embed/js/admin/Gulpfile.js b/extensions/embed/js/admin/Gulpfile.js new file mode 100644 index 000000000..64fa9ad7b --- /dev/null +++ b/extensions/embed/js/admin/Gulpfile.js @@ -0,0 +1,7 @@ +var gulp = require('flarum-gulp'); + +gulp({ + modules: { + 'embed': 'src/**/*.js' + } +}); diff --git a/extensions/embed/js/admin/package.json b/extensions/embed/js/admin/package.json new file mode 100644 index 000000000..62ea6c691 --- /dev/null +++ b/extensions/embed/js/admin/package.json @@ -0,0 +1,7 @@ +{ + "private": true, + "devDependencies": { + "gulp": "^3.8.11", + "flarum-gulp": "^0.1.0" + } +} diff --git a/extensions/embed/js/admin/src/main.js b/extensions/embed/js/admin/src/main.js new file mode 100644 index 000000000..9f10bfdb7 --- /dev/null +++ b/extensions/embed/js/admin/src/main.js @@ -0,0 +1,5 @@ +import app from 'flarum/app'; + +app.initializers.add('embed', () => { + +}); diff --git a/extensions/embed/js/forum/Gulpfile.js b/extensions/embed/js/forum/Gulpfile.js new file mode 100644 index 000000000..64fa9ad7b --- /dev/null +++ b/extensions/embed/js/forum/Gulpfile.js @@ -0,0 +1,7 @@ +var gulp = require('flarum-gulp'); + +gulp({ + modules: { + 'embed': 'src/**/*.js' + } +}); diff --git a/extensions/embed/js/forum/package.json b/extensions/embed/js/forum/package.json new file mode 100644 index 000000000..62ea6c691 --- /dev/null +++ b/extensions/embed/js/forum/package.json @@ -0,0 +1,7 @@ +{ + "private": true, + "devDependencies": { + "gulp": "^3.8.11", + "flarum-gulp": "^0.1.0" + } +} diff --git a/extensions/embed/js/forum/src/components/DiscussionPage.js b/extensions/embed/js/forum/src/components/DiscussionPage.js new file mode 100644 index 000000000..c1384dcfe --- /dev/null +++ b/extensions/embed/js/forum/src/components/DiscussionPage.js @@ -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 ( +
+
+
+
+ {this.stream.render()} +
+
+
+
+ ); + } +} diff --git a/extensions/embed/js/forum/src/main.js b/extensions/embed/js/forum/src/main.js new file mode 100644 index 000000000..0db77bb7b --- /dev/null +++ b/extensions/embed/js/forum/src/main.js @@ -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()); +}); diff --git a/extensions/embed/less/forum/extension.less b/extensions/embed/less/forum/extension.less new file mode 100644 index 000000000..f56c81e02 --- /dev/null +++ b/extensions/embed/less/forum/extension.less @@ -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; +} diff --git a/extensions/embed/locale/en.yml b/extensions/embed/locale/en.yml new file mode 100644 index 000000000..af6a379f8 --- /dev/null +++ b/extensions/embed/locale/en.yml @@ -0,0 +1,2 @@ +embed: + # hello_world: "Hello, world!" diff --git a/extensions/embed/scripts/build.sh b/extensions/embed/scripts/build.sh new file mode 100755 index 000000000..6f86e3b4e --- /dev/null +++ b/extensions/embed/scripts/build.sh @@ -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 < ${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 diff --git a/extensions/embed/scripts/compile.sh b/extensions/embed/scripts/compile.sh new file mode 100755 index 000000000..c8716eca2 --- /dev/null +++ b/extensions/embed/scripts/compile.sh @@ -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 diff --git a/extensions/embed/src/ClientAction.php b/extensions/embed/src/ClientAction.php new file mode 100644 index 000000000..f3742b7b2 --- /dev/null +++ b/extensions/embed/src/ClientAction.php @@ -0,0 +1,46 @@ + + * + * 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; + } +} diff --git a/extensions/embed/src/Extension.php b/extensions/embed/src/Extension.php new file mode 100644 index 000000000..1cb3a0451 --- /dev/null +++ b/extensions/embed/src/Extension.php @@ -0,0 +1,12 @@ +subscribe('Flarum\Embed\Listeners\AddClientAssets'); + } +} diff --git a/extensions/embed/src/Listeners/AddClientAssets.php b/extensions/embed/src/Listeners/AddClientAssets.php new file mode 100644 index 000000000..59921afef --- /dev/null +++ b/extensions/embed/src/Listeners/AddClientAssets.php @@ -0,0 +1,31 @@ +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'); + } +} diff --git a/extensions/embed/views/embed.blade.php b/extensions/embed/views/embed.blade.php new file mode 100644 index 000000000..6f03ce0a5 --- /dev/null +++ b/extensions/embed/views/embed.blade.php @@ -0,0 +1,38 @@ + +
+ +
+
+ + {!! $content !!} + +
+
+
+
+
+
+ +