pageflow-react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,57 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+
4
+ export default function(Component) {
5
+ return {
6
+ scroller: false,
7
+
8
+ enhance(pageElement) {
9
+ this._pageHooks = {...Backbone.Events};
10
+ this._isPreloaded = false;
11
+
12
+ this._render(pageElement);
13
+ },
14
+
15
+ preload(pageElement) {
16
+ this._isPreloaded = true;
17
+ this._render(pageElement);
18
+ },
19
+
20
+ activating(elelement, configuration, options) {
21
+ this._pageHooks.trigger('activating', options);
22
+ },
23
+
24
+ activated() {
25
+ this._pageHooks.trigger('activated');
26
+ },
27
+
28
+ deactivating() {
29
+ this._pageHooks.trigger('deactivating');
30
+ },
31
+
32
+ deactivated() {
33
+ this._pageHooks.trigger('deactivated');
34
+ },
35
+
36
+ resize() {
37
+ this._pageHooks.trigger('resize');
38
+ },
39
+
40
+ update(pageElement, configuration) {
41
+ pageflow.commonPageCssClasses.updateCommonPageCssClasses(pageElement, configuration);
42
+ },
43
+
44
+ cleanup(pageElement) {
45
+ ReactDOM.unmountComponentAtNode(pageElement[0]);
46
+ },
47
+
48
+ _render(pageElement) {
49
+ ReactDOM.render(React.createElement(Component, {
50
+ resolverSeed: pageflow.seed,
51
+ pageId: parseInt(pageElement.attr('id'), 10),
52
+ pageHooks: this._pageHooks,
53
+ isPreloaded: this._isPreloaded
54
+ }), pageElement[0]);
55
+ }
56
+ };
57
+ };
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+
3
+ export default function(Component) {
4
+ return class extends React.Component {
5
+ static childContextTypes = {
6
+ resolverSeed: React.PropTypes.object
7
+ }
8
+
9
+ getChildContext() {
10
+ return {
11
+ resolverSeed: this.props.resolverSeed || {}
12
+ };
13
+ }
14
+
15
+ render() {
16
+ return (
17
+ <Component {...this.props} />
18
+ );
19
+ }
20
+ };
21
+ };
@@ -0,0 +1,3 @@
1
+ import createResolverRoot from './create_resolver_root.jsx';
2
+
3
+ export default createResolverRoot;
@@ -0,0 +1,12 @@
1
+ export default function(Component) {
2
+ return {
3
+ enhance: function(element) {
4
+ ReactDOM.render(React.createElement(Component, {
5
+ resolverSeed: {
6
+ events: pageflow.events,
7
+ ...pageflow.seed
8
+ }
9
+ }), element[0]);
10
+ }
11
+ };
12
+ };
data/js/src/index.js ADDED
@@ -0,0 +1,69 @@
1
+ import createPage from './create_page.jsx';
2
+ import createWidget from './create_widget.jsx';
3
+ import createContainer from './create_container.jsx';
4
+ import createPageType from './create_page_type';
5
+ import createWidgetType from './create_widget_type';
6
+ import createPageComponent from './create_page_component.jsx';
7
+ import resolve from './resolve';
8
+ import mutate from './mutate';
9
+
10
+ import classNames from 'classnames';
11
+
12
+ import PageWrapper from './components/page_wrapper.jsx';
13
+ import PageBackground from './components/page_background.jsx';
14
+ import PageShadow from './components/page_shadow.jsx';
15
+ import PageContent from './components/page_content.jsx';
16
+ import PageHeader from './components/page_header.jsx';
17
+ import PageText from './components/page_text.jsx';
18
+ import BackgroundImage from './components/background_image.jsx';
19
+ import PageBackgroundImage from './components/page_background_image.jsx';
20
+ import PageLink from './components/page_link.jsx';
21
+ import PageThumbnail from './components/page_thumbnail.jsx';
22
+ import LazyLoadedPageThumbnail from './components/lazy_loaded_page_thumbnail.jsx';
23
+
24
+ import Draggable from 'react-draggable';
25
+
26
+ export default {
27
+ /** @api public */
28
+ createContainer,
29
+
30
+ /** @api public */
31
+ createPage,
32
+
33
+ /** @api public */
34
+ createWidget,
35
+
36
+ /** @api public */
37
+ createPageType,
38
+
39
+ /** @api public */
40
+ createWidgetType,
41
+
42
+ /** @api public */
43
+ createPageComponent,
44
+
45
+ /** @api public */
46
+ resolve,
47
+
48
+ /** @api public */
49
+ mutate,
50
+
51
+ classNames,
52
+
53
+ components: {
54
+ PageWrapper,
55
+ PageBackground,
56
+ PageShadow,
57
+ PageContent,
58
+ PageHeader,
59
+ PageText,
60
+ BackgroundImage,
61
+ PageBackgroundImage,
62
+
63
+ PageLink,
64
+ PageThumbnail,
65
+ LazyLoadedPageThumbnail,
66
+
67
+ Draggable
68
+ }
69
+ };
data/js/src/mutate.js ADDED
@@ -0,0 +1,17 @@
1
+ import UpdatePageMutation from './mutations/update_page_mutation';
2
+ import UpdatePageLinkMutation from './mutations/update_page_link_mutation';
3
+
4
+ var mutations = {
5
+ updatePage: UpdatePageMutation,
6
+ updatePageLink: UpdatePageLinkMutation
7
+ };
8
+
9
+ export default function(mutationName, props) {
10
+ var mutation = mutations[mutationName];
11
+
12
+ if (!mutation) {
13
+ throw `Unknown mutation ${mutationName}`;
14
+ }
15
+
16
+ return new mutation(props).perform();
17
+ };
@@ -0,0 +1,5 @@
1
+ export default class {
2
+ constructor(props) {
3
+ this.props = props;
4
+ }
5
+ }
@@ -0,0 +1,30 @@
1
+ import Mutation from './mutation';
2
+
3
+ import pageflow from 'pageflow';
4
+
5
+ export default class extends Mutation {
6
+ perform() {
7
+ this._getPageLink().set(this.props.attributes);
8
+ }
9
+
10
+ _getPageLink() {
11
+ var pageLink = this._getPage().pageLinks().get(this.props.id);
12
+
13
+ if (!pageLink) {
14
+ throw new Error(`Could not find page link with id ${this.props.pageLinkId}.`);
15
+ }
16
+
17
+ return pageLink;
18
+ }
19
+
20
+ _getPage() {
21
+ var [pageId] = this.props.id.split(':');
22
+ var page = pageflow.pages.getByPermaId(pageId);
23
+
24
+ if (!page) {
25
+ throw new Error(`Could not find page with id ${pageId}.`);
26
+ }
27
+
28
+ return page;
29
+ }
30
+ }
@@ -0,0 +1,19 @@
1
+ import Mutation from './mutation';
2
+
3
+ import pageflow from 'pageflow';
4
+
5
+ export default class extends Mutation {
6
+ perform() {
7
+ this._getPage().configuration.set(this.props.attributes);
8
+ }
9
+
10
+ _getPage() {
11
+ var page = pageflow.pages.get(this.props.pageId);
12
+
13
+ if (!page) {
14
+ throw new Error(`Could not find page with id ${this.props.pageId}.`);
15
+ }
16
+
17
+ return page;
18
+ }
19
+ }
data/js/src/resolve.js ADDED
@@ -0,0 +1,45 @@
1
+ import EditorFileIdsResolver from './resolvers/editor_file_ids_resolver';
2
+ import EditorPageResolver from './resolvers/editor_page_resolver';
3
+ import EditorChapterResolver from './resolvers/editor_chapter_resolver';
4
+ import SeedFileIdsResolver from './resolvers/seed_file_ids_resolver';
5
+ import SeedPageResolver from './resolvers/seed_page_resolver';
6
+ import SeedChapterResolver from './resolvers/seed_chapter_resolver';
7
+ import PageTypeResolver from './resolvers/page_type_resolver';
8
+ import CurrentParentPageResolver from './resolvers/current_parent_page_resolver';
9
+ import I18nResolver from './resolvers/i18n_resolver';
10
+
11
+ var resolvers;
12
+
13
+ if (PAGEFLOW_EDITOR) {
14
+ resolvers = {
15
+ fileIds: EditorFileIdsResolver,
16
+ chapter: EditorChapterResolver,
17
+ page: EditorPageResolver
18
+ };
19
+ }
20
+ else {
21
+ resolvers = {
22
+ fileIds: SeedFileIdsResolver,
23
+ chapter: SeedChapterResolver,
24
+ page: SeedPageResolver
25
+ };
26
+ }
27
+
28
+ resolvers = {
29
+ pageType: PageTypeResolver,
30
+ currentParentPage: CurrentParentPageResolver,
31
+ i18n: I18nResolver,
32
+ ...resolvers
33
+ }
34
+
35
+ export default function(resolverName, options) {
36
+ var resolver = resolvers[resolverName];
37
+
38
+ if (!resolver) {
39
+ throw `Unknown resolver ${resolverName}`;
40
+ }
41
+
42
+ return function(callback) {
43
+ return new resolver(options, callback);
44
+ }
45
+ };
@@ -0,0 +1,118 @@
1
+ import Resolver from './resolver';
2
+ import createRecursiveResolver from './create_recursive_resolver';
3
+
4
+ import camelize from '../utils/camelize';
5
+
6
+ /**
7
+ * Resolve a foreign key to an object of attributes.
8
+ */
9
+ class BackboneModelResolver extends Resolver {
10
+ constructor(options, callback) {
11
+ super(callback);
12
+ this._options = {
13
+ idAttribute: 'id',
14
+ attributesForProps: ['id'],
15
+ includeConfiguration: false,
16
+ ...options
17
+ };
18
+ }
19
+
20
+ get(props, seed) {
21
+ this._updateModel(props, seed || {});
22
+ this._updateSubscription();
23
+
24
+ return this._getPropsFromModel();
25
+ }
26
+
27
+ dispose() {
28
+ if (this._model) {
29
+ this._stopListening(this._model);
30
+ }
31
+ }
32
+
33
+ _updateModel(props, seed) {
34
+ this._prevModel = this._model;
35
+ this._model = this._getModel(props, seed);
36
+ }
37
+
38
+ _getModel(props, seed) {
39
+ var collection = this._options.collection(seed.ns);
40
+ return collection.findWhere(this._getIdConditions(props));
41
+ }
42
+
43
+ _getIdConditions(props) {
44
+ var conditions = {};
45
+ conditions[this._options.idAttribute] = this._getModelId(props);
46
+ return conditions;
47
+ }
48
+
49
+ _getModelId(props) {
50
+ return props[this._options.property];
51
+ }
52
+
53
+ _updateSubscription() {
54
+ if (this._prevModel === this._model) {
55
+ return;
56
+ }
57
+
58
+ if (this._prevModel) {
59
+ this._stopListening(this._prevModel);
60
+ }
61
+
62
+ if (this._model) {
63
+ this._startListening(this._model);
64
+ }
65
+ }
66
+
67
+ _startListening(model) {
68
+ model.on(this._getSubscribedEvents(), this._handleChange, this);
69
+
70
+ if (this._options.includeConfiguration) {
71
+ model.configuration.on('change', this._handleChange, this);
72
+ }
73
+ }
74
+
75
+ _stopListening(model) {
76
+ model.off(null, null, this);
77
+
78
+ if (this._options.includeConfiguration) {
79
+ model.configuration.off('change', this._handleChange, this);
80
+ }
81
+ }
82
+
83
+ _getSubscribedEvents() {
84
+ return this._options.attributesForProps
85
+ .map((attribute) => `change:${attribute}`)
86
+ .join(' ');
87
+ }
88
+
89
+ _getPropsFromModel() {
90
+ var props = null;
91
+ var model = this._model;
92
+
93
+ if (model) {
94
+ props = this._getPropsFromAttributes();
95
+
96
+ if (this._options.includeConfiguration) {
97
+ Object.assign(props, camelize.deep(model.configuration.attributes))
98
+ }
99
+ }
100
+
101
+ return props;
102
+ }
103
+
104
+ _getPropsFromAttributes() {
105
+ var model = this._model;
106
+
107
+ return this._options.attributesForProps.reduce((result, name) => {
108
+ if (typeof name === 'string') {
109
+ name = [camelize(name), name];
110
+ }
111
+
112
+ result[name[0]] = model.get(name[1]);
113
+ return result;
114
+ }, {})
115
+ }
116
+ };
117
+
118
+ export default createRecursiveResolver(BackboneModelResolver);
@@ -0,0 +1,20 @@
1
+ import ObjectResolver from './object_resolver';
2
+
3
+ export default function(Resolver) {
4
+ return class {
5
+ constructor(options, callback) {
6
+ this._inner = new Resolver(options, callback);
7
+ this._objectResolver = new ObjectResolver(options.fragments, callback);
8
+ }
9
+
10
+ get(props, seed) {
11
+ const result = this._inner.get(props, seed);
12
+ return this._objectResolver.get(result, seed);
13
+ }
14
+
15
+ dispose() {
16
+ this._inner.dispose();
17
+ this._objectResolver.dispose();
18
+ }
19
+ }
20
+ };
@@ -0,0 +1,38 @@
1
+ import Resolver from './resolver';
2
+ import resolve from '../resolve';
3
+
4
+ import createRecursiveResolver from './create_recursive_resolver';
5
+
6
+ class CurrentPageResolver extends Resolver {
7
+ constructor(options, callback) {
8
+ super(callback);
9
+
10
+ this._subscribeToPageChange();
11
+ this._pageResolver = resolve('page', {property: 'permaId'})(callback);
12
+ }
13
+
14
+ get(_, seed) {
15
+ return this._pageResolver.get({
16
+ permaId: this._currentParentPagePermaId(seed)
17
+ }, seed);
18
+ }
19
+
20
+ dispose() {
21
+ this._unsubscribeFromPageChange();
22
+ }
23
+
24
+ _currentParentPagePermaId(seed) {
25
+ var currentPagePermaId = pageflow.slides.currentPage().page('getPermaId');
26
+ return pageflow.entryData.getParentPagePermaIdByPagePermaId(currentPagePermaId);
27
+ }
28
+
29
+ _subscribeToPageChange() {
30
+ pageflow.events.on('page:change', this._handleChange, this);
31
+ }
32
+
33
+ _unsubscribeFromPageChange() {
34
+ pageflow.events.off('page:change', this._handleChange, this);
35
+ }
36
+ };
37
+
38
+ export default createRecursiveResolver(CurrentPageResolver);