pageflow-react 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.jshintrc +15 -0
  4. data/CHANGELOG.md +7 -0
  5. data/Gemfile +10 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +40 -0
  8. data/Rakefile +4 -0
  9. data/app/assets/javascripts/pageflow/react.js +8975 -0
  10. data/app/assets/javascripts/pageflow/react/components.js +4 -0
  11. data/app/views/pageflow/react/_widget.html.erb +1 -0
  12. data/app/views/pageflow/react/page.html.erb +7 -0
  13. data/js/.eslintrc +33 -0
  14. data/js/.gitignore +1 -0
  15. data/js/karma.conf.js +61 -0
  16. data/js/package.json +43 -0
  17. data/js/spec/.eslintrc +8 -0
  18. data/js/spec/components/background_image_spec.js +47 -0
  19. data/js/spec/components/page_thumbnail_spec.js +213 -0
  20. data/js/spec/create_container_spec.js +82 -0
  21. data/js/spec/resolve_spec.js +3 -0
  22. data/js/spec/resolvers/backbone_model_resolver_spec.js +256 -0
  23. data/js/spec/resolvers/create_recursive_resolver_spec.js +120 -0
  24. data/js/spec/resolvers/editor_file_ids_resolver_spec.js +49 -0
  25. data/js/spec/resolvers/i18n_resolver_spec.js +20 -0
  26. data/js/spec/resolvers/object_resolver_spec.js +165 -0
  27. data/js/spec/resolvers/page_type_resolver_spec.js +23 -0
  28. data/js/spec/resolvers/seed_resolver_spec.js +128 -0
  29. data/js/spec/stub_spec.js +16 -0
  30. data/js/spec/support/render_component.js +7 -0
  31. data/js/src/components/background_image.jsx +60 -0
  32. data/js/src/components/lazy_background_image.jsx +23 -0
  33. data/js/src/components/lazy_loaded_page_thumbnail.jsx +19 -0
  34. data/js/src/components/page_background.jsx +11 -0
  35. data/js/src/components/page_background_image.jsx +13 -0
  36. data/js/src/components/page_content.jsx +51 -0
  37. data/js/src/components/page_header.jsx +15 -0
  38. data/js/src/components/page_link.jsx +35 -0
  39. data/js/src/components/page_shadow.jsx +19 -0
  40. data/js/src/components/page_text.jsx +17 -0
  41. data/js/src/components/page_thumbnail.jsx +86 -0
  42. data/js/src/components/page_wrapper.jsx +11 -0
  43. data/js/src/components/scroller.js +43 -0
  44. data/js/src/create_container.jsx +53 -0
  45. data/js/src/create_page.jsx +38 -0
  46. data/js/src/create_page_component.jsx +45 -0
  47. data/js/src/create_page_type.js +57 -0
  48. data/js/src/create_resolver_root.jsx +21 -0
  49. data/js/src/create_widget.jsx +3 -0
  50. data/js/src/create_widget_type.js +12 -0
  51. data/js/src/index.js +69 -0
  52. data/js/src/mutate.js +17 -0
  53. data/js/src/mutations/mutation.js +5 -0
  54. data/js/src/mutations/update_page_link_mutation.js +30 -0
  55. data/js/src/mutations/update_page_mutation.js +19 -0
  56. data/js/src/resolve.js +45 -0
  57. data/js/src/resolvers/backbone_model_resolver.js +118 -0
  58. data/js/src/resolvers/create_recursive_resolver.js +20 -0
  59. data/js/src/resolvers/current_parent_page_resolver.js +38 -0
  60. data/js/src/resolvers/editor_chapter_resolver.js +10 -0
  61. data/js/src/resolvers/editor_file_ids_resolver.js +30 -0
  62. data/js/src/resolvers/editor_page_resolver.js +11 -0
  63. data/js/src/resolvers/i18n_resolver.js +11 -0
  64. data/js/src/resolvers/object_resolver.js +58 -0
  65. data/js/src/resolvers/page_type_resolver.js +12 -0
  66. data/js/src/resolvers/resolver.js +16 -0
  67. data/js/src/resolvers/seed_chapter_resolver.js +10 -0
  68. data/js/src/resolvers/seed_file_ids_resolver.js +11 -0
  69. data/js/src/resolvers/seed_page_resolver.js +11 -0
  70. data/js/src/resolvers/seed_resolver.js +75 -0
  71. data/js/src/utils/camelize.js +29 -0
  72. data/js/webpack.config.js +31 -0
  73. data/lib/pageflow-react.rb +13 -0
  74. data/lib/pageflow/react/engine.rb +15 -0
  75. data/lib/pageflow/react/page_type.rb +16 -0
  76. data/lib/pageflow/react/version.rb +5 -0
  77. data/lib/pageflow/react/widget_type.rb +21 -0
  78. data/pageflow-react.gemspec +29 -0
  79. metadata +205 -0
@@ -0,0 +1,10 @@
1
+ import BackboneModelResolver from './backbone_model_resolver';
2
+
3
+ export default function(options, callback) {
4
+ return new BackboneModelResolver({
5
+ collection: () => pageflow.chapters,
6
+ attributesForProps: ['id', 'title', 'position'],
7
+ property: 'chapterId',
8
+ ...options
9
+ }, callback);
10
+ };
@@ -0,0 +1,30 @@
1
+ import Resolver from './resolver';
2
+
3
+ export default class extends Resolver {
4
+ constructor(options, callback) {
5
+ super(callback);
6
+ this._options = {
7
+ collections: () => pageflow.files,
8
+ ...options
9
+ };
10
+
11
+ Object.values(this._options.collections()).forEach((collection) =>
12
+ collection.on('remove', this._handleChange, this)
13
+ );
14
+ }
15
+
16
+ get() {
17
+ var files = this._options.collections();
18
+
19
+ return Object.keys(files).reduce((result, collectionName) => {
20
+ result[collectionName] = files[collectionName].map((file) => file.id);
21
+ return result;
22
+ }, {});
23
+ }
24
+
25
+ dispose() {
26
+ Object.values(this._options.collections()).forEach((collection) =>
27
+ collection.off('remove', this._handleChange, this)
28
+ );
29
+ }
30
+ };
@@ -0,0 +1,11 @@
1
+ import BackboneModelResolver from './backbone_model_resolver';
2
+
3
+ export default function(options, callback) {
4
+ return new BackboneModelResolver({
5
+ collection: () => pageflow.pages,
6
+ idAttribute: 'perma_id',
7
+ attributesForProps: ['perma_id', ['type', 'template'], 'chapter_id'],
8
+ includeConfiguration: true,
9
+ ...options
10
+ }, callback);
11
+ };
@@ -0,0 +1,11 @@
1
+ import Resolver from './resolver';
2
+
3
+ export default class extends Resolver {
4
+ get(props, seed) {
5
+ return {
6
+ t: function(key, options) {
7
+ return I18n.t(key, {locale: seed.locale, ...options});
8
+ }
9
+ };
10
+ }
11
+ };
@@ -0,0 +1,58 @@
1
+ import Resolver from './resolver';
2
+
3
+ export default class ObjectResolver extends Resolver {
4
+ constructor(fragment, callback, propertyName) {
5
+ super(callback);
6
+ this._fragment = fragment;
7
+ this._resolvers = {};
8
+ this._propertyName = propertyName;
9
+ }
10
+
11
+ get(props, seed) {
12
+ this._updateResolvers();
13
+
14
+ if (this._propertyName) {
15
+ props = props[this._propertyName];
16
+ }
17
+
18
+ if (!props) {
19
+ return null;
20
+ }
21
+
22
+ return Object.keys(this._resolvers).reduce((result, key) => {
23
+ const resolver = this._resolvers[key];
24
+
25
+ result[key] = resolver.get(props, seed);
26
+ return result;
27
+ }, {...props});
28
+ }
29
+
30
+ dispose() {
31
+ Object.keys(this._resolvers).forEach((key) => {
32
+ this._resolvers[key].dispose();
33
+ });
34
+ }
35
+
36
+ _updateResolvers() {
37
+ var resolvers = this._resolvers;
38
+
39
+ Object.keys(this._fragment || {}).forEach((key) => {
40
+ const resolverProvider = this._fragment[key];
41
+
42
+ if (!resolvers[key]) {
43
+ resolvers[key] = this._createResolver(resolverProvider, key);
44
+ }
45
+ });
46
+ }
47
+
48
+ _createResolver(provider, key) {
49
+ var handleChange = this._handleChange.bind(this);
50
+
51
+ if (typeof provider === 'object') {
52
+ return new ObjectResolver(provider, handleChange, key);
53
+ }
54
+ else {
55
+ return provider(handleChange);
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,12 @@
1
+ import Resolver from './resolver';
2
+
3
+ import camelize from '../utils/camelize';
4
+
5
+ export default class extends Resolver {
6
+ get(props, seed) {
7
+ return {
8
+ name: props.type,
9
+ ...camelize.deep(seed.page_types[props.type])
10
+ };
11
+ }
12
+ };
@@ -0,0 +1,16 @@
1
+ export default class Resolver {
2
+ constructor(callback) {
3
+ this._callback = callback;
4
+ }
5
+
6
+ get(props) {}
7
+
8
+ dispose() {}
9
+
10
+ /** @protected */
11
+ _handleChange() {
12
+ if (this._callback) {
13
+ this._callback();
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,10 @@
1
+ import SeedResolver from './seed_resolver';
2
+
3
+ export default function(options, callback) {
4
+ return new SeedResolver({
5
+ seedProperty: 'chapters',
6
+ attributesForProps: ['id', 'title'],
7
+ property: 'chapterId',
8
+ ...options
9
+ }, callback);
10
+ };
@@ -0,0 +1,11 @@
1
+ import Resolver from './resolver';
2
+
3
+ export default class extends Resolver {
4
+ constructor(_, callback) {
5
+ super(callback);
6
+ }
7
+
8
+ get(props, seed) {
9
+ return seed.file_ids;
10
+ }
11
+ };
@@ -0,0 +1,11 @@
1
+ import SeedResolver from './seed_resolver';
2
+
3
+ export default function(options, callback) {
4
+ return new SeedResolver({
5
+ seedProperty: 'pages',
6
+ idAttribute: 'perma_id',
7
+ attributesForProps: ['perma_id', ['type', 'template'], 'chapter_id'],
8
+ includeConfiguration: true,
9
+ ...options
10
+ }, callback);
11
+ };
@@ -0,0 +1,75 @@
1
+ import Resolver from './resolver';
2
+ import createRecursiveResolver from './create_recursive_resolver';
3
+
4
+ import camelize from '../utils/camelize';
5
+
6
+ /**
7
+ * Resolves a foreign key to an object of attributes from the seed
8
+ * data.
9
+ */
10
+ class SeedResolver extends Resolver {
11
+ constructor(options, callback) {
12
+ super(callback);
13
+
14
+ this._options = {
15
+ idAttribute: 'id',
16
+ attributesForProps: ['id'],
17
+ includeConfiguration: false,
18
+ ...options
19
+ };
20
+ }
21
+
22
+ get(props, seed) {
23
+ var attributes = this._getAttributes(props, seed);
24
+ return this._getProps(attributes);
25
+ }
26
+
27
+ _getAttributes(props, seed) {
28
+ return this._getAttributesById(this._getModelId(props), seed);
29
+ }
30
+
31
+ _getAttributesById(id, seed) {
32
+ const collection = seed[this._options.seedProperty];
33
+
34
+ if (!collection) {
35
+ return null;
36
+ }
37
+
38
+ return collection.find((attributes) => {
39
+ return attributes[this._options.idAttribute] === id;
40
+ });
41
+ }
42
+
43
+ _getModelId(props) {
44
+ return props[this._options.property];
45
+ }
46
+
47
+ _getProps(attributes) {
48
+ var props;
49
+
50
+ if (!attributes) {
51
+ return null;
52
+ }
53
+
54
+ props = this._getPropsFromAttributes(attributes);
55
+
56
+ if (this._options.includeConfiguration) {
57
+ Object.assign(props, camelize.deep(attributes.configuration));
58
+ }
59
+
60
+ return props;
61
+ }
62
+
63
+ _getPropsFromAttributes(attributes) {
64
+ return this._options.attributesForProps.reduce((result, name) => {
65
+ if (typeof name === 'string') {
66
+ name = [camelize(name), name];
67
+ }
68
+
69
+ result[name[0]] = attributes[name[1]];
70
+ return result;
71
+ }, {})
72
+ }
73
+ };
74
+
75
+ export default createRecursiveResolver(SeedResolver);
@@ -0,0 +1,29 @@
1
+ function camelize(snakeCase) {
2
+ return snakeCase.replace(/_[a-z]/g, function(match) {
3
+ return match[1].toUpperCase();
4
+ });
5
+ };
6
+
7
+ camelize.keys = function(object) {
8
+ return Object.keys(object).reduce((result, key) => {
9
+ result[camelize(key)] = object[key];
10
+ return result;
11
+ }, {});
12
+ };
13
+
14
+ camelize.deep = function(object) {
15
+ if (Array.isArray(object)) {
16
+ return object.map(camelize.deep);
17
+ }
18
+ else if (typeof object === 'object' && object) {
19
+ return Object.keys(object).reduce((result, key) => {
20
+ result[camelize(key)] = camelize.deep(object[key]);
21
+ return result;
22
+ }, {});
23
+ }
24
+ else {
25
+ return object;
26
+ }
27
+ };
28
+
29
+ export default camelize;
@@ -0,0 +1,31 @@
1
+ module.exports = {
2
+ context: __dirname + '/src',
3
+ entry: [
4
+ 'babel-polyfill',
5
+ './index.js'
6
+ ],
7
+
8
+ module: {
9
+ loaders: [
10
+ {
11
+ test: /\.jsx?$/,
12
+ exclude: /node_modules/,
13
+ loaders: ['babel-loader?stage=0'],
14
+ }
15
+ ],
16
+ },
17
+
18
+ output: {
19
+ path: __dirname + '/../app/assets/javascripts/pageflow',
20
+ filename: 'react.js',
21
+
22
+ libraryTarget: 'assign',
23
+ library: ['pageflow', 'react']
24
+ },
25
+
26
+ externals: {
27
+ pageflow: 'pageflow',
28
+ react: 'React',
29
+ 'react-dom': 'ReactDOM'
30
+ }
31
+ };
@@ -0,0 +1,13 @@
1
+ require 'pageflow/react/engine'
2
+
3
+ module Pageflow
4
+ module React
5
+ def self.create_page_type(name, component_name)
6
+ Pageflow::React::PageType.new(name, component_name)
7
+ end
8
+
9
+ def self.create_widget_type(name, role, component_name)
10
+ Pageflow::React::WidgetType.new(name, role, component_name)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ require 'react-rails'
2
+
3
+ module Pageflow
4
+ module React
5
+ class Engine < Rails::Engine
6
+ isolate_namespace Pageflow::React
7
+
8
+ config.autoload_paths << File.join(config.root, 'lib')
9
+
10
+ initializer "pageflow-react.add_watchable_files", group: :all do |app|
11
+ app.config.watchable_files.concat Dir["#{config.root}/app/assets/javascripts/**/*.jsx*"]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ module Pageflow
2
+ module React
3
+ class PageType < Pageflow::PageType
4
+ attr_reader :name, :component_name
5
+
6
+ def initialize(name, component_name)
7
+ @name = name
8
+ @component_name = component_name
9
+ end
10
+
11
+ def template_path
12
+ 'pageflow/react/page'
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ module Pageflow
2
+ module React
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,21 @@
1
+ module Pageflow
2
+ module React
3
+ class WidgetType < Pageflow::WidgetType
4
+ attr_reader :name, :role, :component_name
5
+
6
+ def initialize(name, role, component_name)
7
+ @name = name
8
+ @role = role
9
+ @component_name = component_name
10
+ end
11
+
12
+ def roles
13
+ [role]
14
+ end
15
+
16
+ def render(template, _)
17
+ template.render(File.join('pageflow', 'react', 'widget'), name: name)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pageflow/react/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pageflow-react"
8
+ spec.version = Pageflow::React::VERSION
9
+ spec.authors = ["Tim Fischbach"]
10
+ spec.email = ["mail@timfischbach.de"]
11
+ spec.summary = %q{Building Pageflow page types with React.js}
12
+ spec.homepage = "https://github.com/codevise/pageflow-react"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency "pageflow", "~> 0.10"
21
+ spec.add_dependency "react-rails", "~> 1.6.0"
22
+ spec.add_dependency "multi_json", "~> 1.11"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+
27
+ # Semantic versioning rake tasks
28
+ spec.add_development_dependency 'semmy', '~> 0.2'
29
+ end