pageflow-react 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.jshintrc +15 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +40 -0
- data/Rakefile +4 -0
- data/app/assets/javascripts/pageflow/react.js +8975 -0
- data/app/assets/javascripts/pageflow/react/components.js +4 -0
- data/app/views/pageflow/react/_widget.html.erb +1 -0
- data/app/views/pageflow/react/page.html.erb +7 -0
- data/js/.eslintrc +33 -0
- data/js/.gitignore +1 -0
- data/js/karma.conf.js +61 -0
- data/js/package.json +43 -0
- data/js/spec/.eslintrc +8 -0
- data/js/spec/components/background_image_spec.js +47 -0
- data/js/spec/components/page_thumbnail_spec.js +213 -0
- data/js/spec/create_container_spec.js +82 -0
- data/js/spec/resolve_spec.js +3 -0
- data/js/spec/resolvers/backbone_model_resolver_spec.js +256 -0
- data/js/spec/resolvers/create_recursive_resolver_spec.js +120 -0
- data/js/spec/resolvers/editor_file_ids_resolver_spec.js +49 -0
- data/js/spec/resolvers/i18n_resolver_spec.js +20 -0
- data/js/spec/resolvers/object_resolver_spec.js +165 -0
- data/js/spec/resolvers/page_type_resolver_spec.js +23 -0
- data/js/spec/resolvers/seed_resolver_spec.js +128 -0
- data/js/spec/stub_spec.js +16 -0
- data/js/spec/support/render_component.js +7 -0
- data/js/src/components/background_image.jsx +60 -0
- data/js/src/components/lazy_background_image.jsx +23 -0
- data/js/src/components/lazy_loaded_page_thumbnail.jsx +19 -0
- data/js/src/components/page_background.jsx +11 -0
- data/js/src/components/page_background_image.jsx +13 -0
- data/js/src/components/page_content.jsx +51 -0
- data/js/src/components/page_header.jsx +15 -0
- data/js/src/components/page_link.jsx +35 -0
- data/js/src/components/page_shadow.jsx +19 -0
- data/js/src/components/page_text.jsx +17 -0
- data/js/src/components/page_thumbnail.jsx +86 -0
- data/js/src/components/page_wrapper.jsx +11 -0
- data/js/src/components/scroller.js +43 -0
- data/js/src/create_container.jsx +53 -0
- data/js/src/create_page.jsx +38 -0
- data/js/src/create_page_component.jsx +45 -0
- data/js/src/create_page_type.js +57 -0
- data/js/src/create_resolver_root.jsx +21 -0
- data/js/src/create_widget.jsx +3 -0
- data/js/src/create_widget_type.js +12 -0
- data/js/src/index.js +69 -0
- data/js/src/mutate.js +17 -0
- data/js/src/mutations/mutation.js +5 -0
- data/js/src/mutations/update_page_link_mutation.js +30 -0
- data/js/src/mutations/update_page_mutation.js +19 -0
- data/js/src/resolve.js +45 -0
- data/js/src/resolvers/backbone_model_resolver.js +118 -0
- data/js/src/resolvers/create_recursive_resolver.js +20 -0
- data/js/src/resolvers/current_parent_page_resolver.js +38 -0
- data/js/src/resolvers/editor_chapter_resolver.js +10 -0
- data/js/src/resolvers/editor_file_ids_resolver.js +30 -0
- data/js/src/resolvers/editor_page_resolver.js +11 -0
- data/js/src/resolvers/i18n_resolver.js +11 -0
- data/js/src/resolvers/object_resolver.js +58 -0
- data/js/src/resolvers/page_type_resolver.js +12 -0
- data/js/src/resolvers/resolver.js +16 -0
- data/js/src/resolvers/seed_chapter_resolver.js +10 -0
- data/js/src/resolvers/seed_file_ids_resolver.js +11 -0
- data/js/src/resolvers/seed_page_resolver.js +11 -0
- data/js/src/resolvers/seed_resolver.js +75 -0
- data/js/src/utils/camelize.js +29 -0
- data/js/webpack.config.js +31 -0
- data/lib/pageflow-react.rb +13 -0
- data/lib/pageflow/react/engine.rb +15 -0
- data/lib/pageflow/react/page_type.rb +16 -0
- data/lib/pageflow/react/version.rb +5 -0
- data/lib/pageflow/react/widget_type.rb +21 -0
- data/pageflow-react.gemspec +29 -0
- 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,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,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,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
|