pageflow-localfocus 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -2
  3. data/CHANGELOG.md +23 -0
  4. data/CODE_OF_CONDUCT.md +74 -0
  5. data/Gemfile.lock +9 -5
  6. data/LICENSE +21 -0
  7. data/README.md +58 -3
  8. data/app/assets/images/pageflow/localfocus/themes/default/page_type_pictograms/background_image/sprite.png +0 -0
  9. data/app/assets/images/pageflow/localfocus/themes/default/page_type_pictograms/background_image/wide.png +0 -0
  10. data/app/assets/images/pageflow/localfocus_pictogram_small.png +0 -0
  11. data/app/assets/javascripts/pageflow/localfocus.js +1 -1
  12. data/app/assets/javascripts/pageflow/localfocus/components.js +1 -1
  13. data/app/assets/javascripts/pageflow/localfocus/components/frame.jsx +26 -0
  14. data/app/assets/javascripts/pageflow/localfocus/components/page.jsx +16 -7
  15. data/app/assets/javascripts/pageflow/localfocus/editor/templates/url_input.jst.ejs +5 -8
  16. data/app/assets/javascripts/pageflow/localfocus/editor/views/configuration_editor_view.js +15 -7
  17. data/app/assets/javascripts/pageflow/localfocus/editor/views/inputs/url_input_view.js +24 -26
  18. data/app/assets/javascripts/pageflow/localfocus/widgets.js +2 -0
  19. data/app/assets/javascripts/pageflow/localfocus/widgets/loading_spinner.js +27 -0
  20. data/app/assets/stylesheets/pageflow/localfocus.scss +7 -0
  21. data/bin/rails +14 -0
  22. data/config/locales/en.yml +39 -4
  23. data/lib/pageflow/localfocus.rb +1 -1
  24. data/lib/pageflow/localfocus/engine.rb +4 -0
  25. data/lib/pageflow/localfocus/plugin.rb +3 -1
  26. data/lib/pageflow/localfocus/version.rb +1 -1
  27. data/pageflow-localfocus.gemspec +1 -0
  28. data/vendor/assets/javascripts/localfocusapi.js +220 -0
  29. metadata +16 -4
  30. data/app/assets/javascripts/pageflow/localfocus/components/localfocus_iframe.jsx +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6a7dd9a5f87f2f9508451d84662fa2a878193f26
4
- data.tar.gz: 5544a4aaff0c0d8bd14ccc50efd641f8d2d4ae7e
3
+ metadata.gz: 669a2ff3409e820dc66cd1c716c7930fa26cf035
4
+ data.tar.gz: a3bb15be212d688eb5934be3e4e84574552f7f9a
5
5
  SHA512:
6
- metadata.gz: 7ee6ac8bb5cbfc63a7e5366d9be12dd86bbb4cfb8b33e814af4fb4b1b0b99bbf1d431e98ff0dd3ffdde3ed36961d24cb331d9f6e95f27e522c4e172151c9e945
7
- data.tar.gz: ab3528a42ce55e87edcd9850b1b94c136e9ef03b4128eb8d66b8dc54829e781b0ba8f86ee87556e1aaf75f824f546633bd01f7da434fc22609508a96f62c54ea
6
+ metadata.gz: 123025b2b708f4086f5335b6bd5b5a0dd842a10bc43748cd1ca498b72ddb18bd981c9d52520ea3378e49aa769f873166a93fcf3441533d5ac2602484b4bc4e70
7
+ data.tar.gz: 42405d5a3d1608cb6561037f59aea3a0d10c128c1f4318c13a4e1be87072178c6204f68fef2acb4a39ebd7b2be5641c6ef710d56b2996f6177c8fc10efee97e2
data/.rspec CHANGED
@@ -1,3 +1 @@
1
- --format documentation
2
- --color
3
1
  --require spec_helper
data/CHANGELOG.md ADDED
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.0.0] - 2017-06-20
10
+ ### Added
11
+ - Embed LocalFocus graphs using their _Direct Link_
12
+ - The Page Type is in React, per Pageflow 12 standards
13
+ - Custom pane in the editor
14
+ - Helpful README and [blog made during coding](https://www.spacebabies.nl/portfolio/lets-build-something-new/)
15
+
16
+ ### Changed
17
+
18
+ ### Removed
19
+
20
+
21
+
22
+ [Unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...HEAD
23
+ [1.0.0]: https://github.com/olivierlacan/keep-a-changelog/compare/init...v1.0.0
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ education, socio-economic status, nationality, personal appearance, race,
10
+ religion, or sexual identity and orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at team@scrollytelling.io. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72
+
73
+ [homepage]: https://www.contributor-covenant.org
74
+
data/Gemfile.lock CHANGED
@@ -283,10 +283,6 @@ GEM
283
283
  resque_mailer (2.4.3)
284
284
  actionmailer (>= 3.0)
285
285
  activesupport (>= 3.0)
286
- rspec (3.7.0)
287
- rspec-core (~> 3.7.0)
288
- rspec-expectations (~> 3.7.0)
289
- rspec-mocks (~> 3.7.0)
290
286
  rspec-core (3.7.0)
291
287
  rspec-support (~> 3.7.0)
292
288
  rspec-expectations (3.7.0)
@@ -295,6 +291,14 @@ GEM
295
291
  rspec-mocks (3.7.0)
296
292
  diff-lcs (>= 1.2.0, < 2.0)
297
293
  rspec-support (~> 3.7.0)
294
+ rspec-rails (3.7.2)
295
+ actionpack (>= 3.0)
296
+ activesupport (>= 3.0)
297
+ railties (>= 3.0)
298
+ rspec-core (~> 3.7.0)
299
+ rspec-expectations (~> 3.7.0)
300
+ rspec-mocks (~> 3.7.0)
301
+ rspec-support (~> 3.7.0)
298
302
  rspec-support (3.7.0)
299
303
  rufus-scheduler (2.0.24)
300
304
  tzinfo (>= 0.3.22)
@@ -350,7 +354,7 @@ DEPENDENCIES
350
354
  bundler (~> 1.16)
351
355
  pageflow-localfocus!
352
356
  rake (~> 10.0)
353
- rspec (~> 3.0)
357
+ rspec-rails (~> 3.0)
354
358
 
355
359
  BUNDLED WITH
356
360
  1.16.0
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Scrollytelling
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -1,8 +1,29 @@
1
- # Localfocus integration for Pageflow
1
+ # 📊 LocalFocus integration for Pageflow
2
+
3
+ [LocalFocus](https://www.localfocus.nl/en/) lets you create and share
4
+ animated illustrations for a wide range of datasets. [Example](https://localfocus2.appspot.com/551a9626918b3)
5
+
6
+ What you are reading now
7
+ is a custom integration with Open Source storytelling tool [Pageflow](https://pageflow.io). And it's brought to you by [☢Scrollytelling☣](https://www.scrollytelling.io):
8
+ two Amsterdammers❌❌❌ in pyjama with their unstoppable storytelling tank. You're welcome!
9
+
10
+ ### Includes LocalFocus API
11
+
12
+ The official [LocalFocus JavaScript Widget SDK](https://developers.localfocus.nl/widgets/) is bundled with this plugin.
13
+
14
+ ```
15
+ Version: 1.1
16
+ Date: 09-01-2017
17
+ ```
18
+
19
+ We use it to show a spinner while the chart is loading in the background. When
20
+ everything is ready, the chart appears in place. Smooth operator!
2
21
 
3
22
 
4
23
  ## Installation
5
24
 
25
+ _(Assuming you know your way around a Rails application and a Unix terminal.)_
26
+
6
27
  Add this line to your application's Gemfile:
7
28
 
8
29
  ```ruby
@@ -13,11 +34,42 @@ And then execute:
13
34
 
14
35
  $ bundle
15
36
 
37
+ Register the plugin:
38
+
39
+ ``` ruby
40
+ # config/initializers/pageflow.rb
41
+ Pageflow.configure do |config|
42
+ config.plugin(Pageflow::Localfocus.plugin)
43
+ end
44
+ ```
45
+
46
+ Include javascripts and stylesheets:
47
+
48
+ # app/assets/javascripts/components.js
49
+ //= require "pageflow/localfocus/components"
50
+
51
+ # app/assets/javascripts/pageflow/application.js
52
+ //= require "pageflow/localfocus"
53
+
54
+ # app/assets/javascripts/pageflow/editor.js
55
+ //= require pageflow/localfocus/editor
56
+
57
+ # app/assets/stylesheets/pageflow/application.scss
58
+ @import "pageflow/localfocus";
59
+
60
+ Now you can enable the page type in your feature settings.
61
+
16
62
  ## Usage
17
63
 
18
- TODO: Write usage instructions here
64
+ 1. Login as an editor and open any story in the editor
65
+ 2. Add a new page and choose type **LocalFocus**
66
+ 3. In the *Widget* tab, enter the graph URL you want to show
67
+
68
+ The graph should appear right away. Happy graphing!
19
69
 
20
- ## Development
70
+ ## Want to help developing this plugin?
71
+
72
+ That's cool and help is always needed!
21
73
 
22
74
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
23
75
 
@@ -26,3 +78,6 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
26
78
  ## Contributing
27
79
 
28
80
  Bug reports and pull requests are welcome on GitHub at https://github.com/scrollytelling/pageflow-localfocus.
81
+
82
+ Photo by Billy Huynh on Unsplash
83
+ https://unsplash.com/photos/W8KTS-mhFUE
@@ -1,5 +1,5 @@
1
1
  //= require_self
2
-
2
+ //= require localfocusapi
3
3
  //= require ./localfocus/components
4
4
 
5
5
  pageflow.localfocus = pageflow.localfocus || {};
@@ -1,5 +1,5 @@
1
1
  //= require_self
2
- //= require ./components/localfocus_iframe
2
+ //= require ./components/frame
3
3
  //= require ./components/page
4
4
 
5
5
  pageflow.localfocus = pageflow.localfocus || {};
@@ -0,0 +1,26 @@
1
+ (function() {
2
+ class Frame extends React.Component {
3
+ render() {
4
+ return (
5
+ <div className="lf-frame">
6
+ <div className="lf-loading"></div>
7
+ <iframe
8
+ src={this.props.page.localfocusUrl}
9
+ className={this.props.className}
10
+ ref={iframe => this.iframe = iframe}
11
+ >
12
+ </iframe>
13
+ </div>
14
+ )
15
+ }
16
+ }
17
+
18
+ Frame.defaultProps = {
19
+ className: 'localfocusvisual lf-iframe'
20
+ }
21
+
22
+ const {connectInPage, combine} = pageflow.react;
23
+
24
+ pageflow.localfocus.Frame = connectInPage(combine({
25
+ }))(Frame);
26
+ }());
@@ -1,26 +1,30 @@
1
1
  (function() {
2
2
  const {
3
3
  PageWrapper,
4
- PageBackground, PageBackgroundImage, PageShadow,
4
+ MediaPageBackground, PageBackgroundImage, PageShadow,
5
5
  PageContent, PageHeader, PageText
6
6
  } = pageflow.react.components;
7
7
 
8
8
  const {
9
- LocalfocusIframe
9
+ Frame
10
10
  } = pageflow.localfocus;
11
11
 
12
12
  class Page extends React.Component {
13
+ constructor(props) {
14
+ super(props);
15
+ }
16
+
13
17
  render() {
14
18
  return (
15
19
  <PageWrapper>
16
- <PageBackground>
17
- </PageBackground>
20
+ <MediaPageBackground page={this.props.page} />
18
21
 
19
22
  <PageContent>
20
- <LocalfocusIframe/>
23
+ <Frame page={this.props.page}/>
24
+ <PageText page={this.props.page} />
21
25
  </PageContent>
22
26
  </PageWrapper>
23
- )
27
+ );
24
28
  }
25
29
  }
26
30
 
@@ -32,6 +36,11 @@
32
36
  combine({
33
37
  page: pageAttributes()
34
38
  })
35
- )(Page)
39
+ )(Page),
40
+
41
+ // Enable page state reducers and sagas to handle playback
42
+ reduxModules: [
43
+ pageflow.react.mediaPageBackgroundReduxModule
44
+ ]
36
45
  });
37
46
  }());
@@ -1,12 +1,9 @@
1
1
  <label>
2
2
  <span class="name"></span>
3
3
  <span class="inline_help"></span>
4
- <input
5
- type="url"
6
- required pattern="https://localfocus2.appspot.com/.*"
7
- title="Only localfocus URLs are allowed"
8
- placeholder="https://localfocus2.appspot.com/551a9626918b3"
9
- />
10
4
  </label>
11
- <div class="validation"></div>
12
- <div class="status_container"></div>
5
+ <input
6
+ type="url"
7
+ required pattern="https://localfocus2.appspot.com/.*"
8
+ placeholder="https://localfocus2.appspot.com/551a9626918b3"
9
+ />
@@ -1,18 +1,26 @@
1
1
  pageflow.localfocus.ConfigurationEditorView = pageflow.ConfigurationEditorView.extend({
2
2
  configure: function() {
3
3
  this.tab('general', function() {
4
- this.group('general');
4
+ this.input('text', pageflow.TextAreaInputView);
5
+ this.input('text_position', pageflow.SelectInputView, {values: pageflow.Page.textPositions});
5
6
  });
6
7
 
7
- this.tab('files', function() {
8
- this.input('link', pageflow.localfocus.UrlInputView, {
9
- required: true,
10
- pattern: "https://localfocus2.appspot.com/.*", // I18n.t('pageflow.localfocus.placeholder', {locale: pageflow.entry.configuration.get('locale')})
11
- title: "Only localfocus URLs are allowed",
12
- placeholder: "https://localfocus2.appspot.com/551a9626918b3"
8
+ this.tab('widget', function() {
9
+ this.input('chart', pageflow.localfocus.UrlInputView, {
10
+ propertyName: 'localfocus_url'
13
11
  })
14
12
  });
15
13
 
14
+ this.tab('files', function() {
15
+ // Renders background type select box and file input views
16
+ this.group('background');
17
+
18
+ this.input('thumbnail_image_id', pageflow.FileInputView, {
19
+ collection: 'image_files',
20
+ positioning: false
21
+ });
22
+ });
23
+
16
24
  this.tab('options', function() {
17
25
  this.group('options');
18
26
  });
@@ -1,53 +1,51 @@
1
1
  /**
2
- * Input view for an URL.
2
+ * Input view for a single line of text.
3
+ *
4
+ * @param {boolean} [options.required=false]
5
+ * Display an error if the input is blank.
6
+ *
7
+ * @see
8
+ * {@link module:pageflow/ui.pageflow.inputWithPlaceholderText pageflow.inputWithPlaceholderText}
9
+ * for placeholder related further options
3
10
  *
4
11
  * @see {@link module:pageflow/ui.pageflow.inputView pageflow.inputView} for further options
5
12
  * @class
6
- * @memberof module:pageflow/localfocus
13
+ * @memberof module:pageflow/ui
7
14
  */
8
15
  pageflow.localfocus.UrlInputView = Backbone.Marionette.ItemView.extend({
9
- mixins: [pageflow.inputView],
16
+ mixins: [pageflow.inputView, pageflow.inputWithPlaceholderText],
10
17
 
11
- template: 'pageflow/chart/editor/templates/url_input',
18
+ template: 'pageflow/localfocus/editor/templates/url_input',
12
19
 
13
20
  ui: {
14
21
  input: 'input'
15
22
  },
16
23
 
24
+ events: {
25
+ 'blur input': 'validate'
26
+ },
27
+
17
28
  onRender: function() {
18
- load();
29
+ this.ui.input.attr('title', I18n.t('pageflow.ui.views.inputs.text_input_view.required_field'));
30
+ this.load();
19
31
  },
20
32
 
21
- onChange: function() {
22
- save();
23
- validate();
33
+ save: function() {
34
+ this.model.set(this.options.propertyName, this.ui.input.val());
24
35
  },
25
36
 
26
37
  load: function() {
27
38
  this.ui.input.val(this.model.get(this.options.propertyName));
28
- this.listenTo(this.ui.input, 'input', this.onChange);
29
- },
30
-
31
- save: function() {
32
- this.model.set(this.options.propertyName, this.ui.input.val());
33
39
  },
34
40
 
35
41
  validate: function() {
36
- if (this.ui.input.validity.valid) {
37
- this.resetValidationError();
42
+ input = this.ui.input[0];
43
+ if (input.checkValidity()) {
44
+ this.$el.removeClass('invalid');
45
+ this.save();
38
46
  }
39
47
  else {
40
- this.displayValidationError(I18n.t('pageflow.localfocus.views.inputs.text_input_view.required_field'));
48
+ this.$el.addClass('invalid');
41
49
  }
42
- },
43
-
44
- displayValidationError: function(message) {
45
- this.$el.addClass('invalid');
46
- this.ui.input.attr('title', message);
47
- },
48
-
49
- resetValidationError: function(message) {
50
- this.$el.removeClass('invalid');
51
- this.ui.input.attr('title', '');
52
50
  }
53
51
  });
@@ -0,0 +1,2 @@
1
+ //= require_self
2
+ //= require ./widgets/loading_spinner
@@ -0,0 +1,27 @@
1
+ // #example-spinner {
2
+ // width: 100%;
3
+ // height: 450px;
4
+ // position:absolute;
5
+ // background-image: url('spinner.svg');
6
+ // background-position: center center;
7
+ // background-repeat: no-repeat;
8
+ // background-size: 4em;
9
+ // }
10
+ //
11
+ // #example {
12
+ // opacity:0;
13
+ // width:100%;
14
+ // height:450px;
15
+ // overflow:hidden;
16
+ // }
17
+
18
+
19
+ LocalFocusAPI.selectAll('.localfocusvisual', function() {
20
+ this.on('loaded', function() {
21
+ console.log('loaded');
22
+ });
23
+
24
+ this.on('ready', function() {
25
+ console.log('ready');
26
+ });
27
+ }
@@ -0,0 +1,7 @@
1
+ @include pageflow-page-type(localfocus);
2
+
3
+ .lf-iframe {
4
+ width: 100%;
5
+ height: 70vh;
6
+ overflow: hidden;
7
+ }
data/bin/rails ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails gems
3
+ # installed from the root of your application.
4
+
5
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
6
+ ENGINE_PATH = File.expand_path('../../lib/pageflow/localfocus/engine', __FILE__)
7
+ APP_PATH = File.expand_path('../../test/dummy/config/application', __FILE__)
8
+
9
+ # Set up gems listed in the Gemfile.
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
11
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
12
+
13
+ require 'rails/all'
14
+ require 'rails/engine/commands'
@@ -1,10 +1,45 @@
1
1
  en:
2
2
  pageflow:
3
3
  localfocus:
4
- page_type_name: Localfocus
5
- page_type_description: Embed a Localfocus chart
4
+ page_attributes:
5
+ localfocus_url:
6
+ label: Graph URL
7
+ inline_help: Paste the direct link to the graph here. In LocalFocus, see the “Create” tab, click _Widget_, then copy the _Direct Link_.
8
+ page_type_feature:
9
+ name: LocalFocus page type
10
+ page_type_name: LocalFocus
11
+ page_type_description: Embed a LocalFocus chart
6
12
  page_type_category_name: Data and Charts
7
13
  help_entries:
8
14
  page_type:
9
- menu_item: Localfocus
10
- text: Paste the localfocus URL in the field.
15
+ menu_item: LocalFocus
16
+ text: |-
17
+ Select this Page Type to embed a [LocalFocus](https://www.localfocus.nl/en/) graph.
18
+
19
+ LocalFocus lets you create and share animated illustrations for a
20
+ wide range of datasets. [Example](https://localfocus2.appspot.com/551a9626918b3)
21
+
22
+ ### In LocalFocus
23
+
24
+ To embed one in a story, first login to LocalFocus and find the
25
+ chart in question. Around half-way on the page you'll see two tabs.
26
+ One labelled _Explore_ and the other _Create_. Choose Create.
27
+
28
+ The sharing options are displayed as red buttons. Choose for
29
+ **Widget** here. Then copy the value of _Direct Link_. You don't
30
+ need to use the complete Embed code; we take care of that for you.
31
+
32
+ ### In Pageflow
33
+
34
+ Now onto your story and the Pageflow editor. Login to Pageflow and
35
+ add a new page. For Page Type, choose _LocalFocus_. Then click the
36
+ _Widget_ tab. Paste the _Direct Link_ into the box. The graph
37
+ should render in the preview pane on the right.
38
+ ui:
39
+ configuration_editor:
40
+ tabs:
41
+ widget: Widget
42
+ views:
43
+ inputs:
44
+ url_input_view:
45
+ title: Alleen URLs van LocalFocus worden ondersteund
@@ -3,7 +3,7 @@ require 'pageflow/localfocus/engine'
3
3
  module Pageflow
4
4
  module Localfocus
5
5
  def self.plugin
6
- Plugin.new
6
+ Localfocus::Plugin.new
7
7
  end
8
8
 
9
9
  def self.page_type
@@ -5,6 +5,10 @@ module Pageflow
5
5
 
6
6
  config.autoload_paths << File.join(config.root, 'lib')
7
7
 
8
+ config.generators do |g|
9
+ g.test_framework :rspec
10
+ end
11
+
8
12
  # This has been fixed in newer versions of react-rails.
9
13
  initializer "pageflow-localfocus.add_watchable_files", group: :all do |app|
10
14
  app.config.watchable_files.concat Dir["#{config.root}/app/assets/javascripts/**/*.jsx*"]
@@ -2,7 +2,9 @@ module Pageflow
2
2
  module Localfocus
3
3
  class Plugin < Pageflow::Plugin
4
4
  def configure(config)
5
- config.page_types.register(Pageflow::Localfocus.page_type)
5
+ config.features.register(PageTypeFeature.new(Localfocus.page_type))
6
+
7
+ config.help_entries.register('pageflow.localfocus.help_entries.page_type', priority: 49)
6
8
  end
7
9
  end
8
10
  end
@@ -1,5 +1,5 @@
1
1
  module Pageflow
2
2
  module Localfocus
3
- VERSION = "0.1.0"
3
+ VERSION = "1.0.0"
4
4
  end
5
5
  end
@@ -12,6 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.summary = "Localfocus charts integration for Pageflow"
13
13
  spec.description = "Localfocus charts integration for Pageflow"
14
14
  spec.homepage = "https://github.com/scrollytelling/pageflow-localfocus"
15
+ spec.license = "MIT"
15
16
 
16
17
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
18
  f.match(%r{^(test|spec|features)/})
@@ -0,0 +1,220 @@
1
+ /* LocalFocus API
2
+ Version: 1.1
3
+ Date: 09-01-2017
4
+ By Erik Willems (twitter: @ehwillems)
5
+ */
6
+
7
+ var LocalFocusAPI = (function(){
8
+ var oldBrowser = ((!window.SVGAngle && !document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Shape", "1.1")) || !document.addEventListener || !document.querySelectorAll);
9
+
10
+ var allowedOrigins = [];
11
+
12
+ function widgetObject(e){
13
+ var element = e, onFunctions = {}, w = this, listener = null;
14
+
15
+ var listen = function(){
16
+ if(!listener){
17
+ listener = function(e) {
18
+ // Check source
19
+ if(e.source !== element.contentWindow){
20
+ return;
21
+ }
22
+ // Check origin
23
+ if(allowedOrigins.length && allowedOrigins.indexOf(e.origin) === -1){
24
+ return;
25
+ }
26
+
27
+ var message;
28
+ try {
29
+ message = JSON.parse(e.data);
30
+ } catch (e) {
31
+ return;
32
+ }
33
+
34
+ if(typeof message !== 'object' || message.type !== 'LocalFocusAPI'){
35
+ return;
36
+ }
37
+ var request = message.request;
38
+
39
+ // Listen to loaded and ready events
40
+ if((request.action === 'loaded' || request.action === 'ready') && typeof onFunctions[request.action] === 'function'){
41
+ onFunctions[request.action].call(w);
42
+ //delete onFunctions[request.action];
43
+ }
44
+
45
+ // Listen to click events
46
+ if(request.action === 'click' && typeof onFunctions[request.action] === 'function'){
47
+ onFunctions[request.action].call(w, request.item);
48
+ }
49
+
50
+ // Listen to interact events
51
+ if(request.action === 'interact' && typeof onFunctions[request.action] === 'function'){
52
+ onFunctions[request.action].call(w, request.type, request.subType);
53
+ }
54
+
55
+ if(request.action === 'setDataStore' && typeof onFunctions.special === 'function'){
56
+ var d = request.dataStore;
57
+ var respond = {
58
+ 'groups':d.groups,
59
+ 'items':d.items,
60
+ 'styling':d.styling,
61
+ 'settings':d.settings
62
+ }
63
+ if(d.records){
64
+ respond.records = d.records;
65
+ }
66
+ onFunctions.special.call(w, respond);
67
+ delete onFunctions.special;
68
+ }
69
+
70
+ if(request.action === 'getDownload' && typeof onFunctions['getDownload'] === 'function'){
71
+ var url = (request.id)? e.origin + '/download/get/' + request.id: null;
72
+ onFunctions['getDownload'].call(w, {'url': url});
73
+ delete onFunctions['getDownload'];
74
+ }
75
+ };
76
+ window.addEventListener("message",listener,false);
77
+ }
78
+ }
79
+
80
+ var send = function(request){
81
+ var message = {
82
+ type: 'LocalFocusAPI',
83
+ request: request
84
+ };
85
+ element.contentWindow.postMessage(JSON.stringify(message),"*");
86
+ }
87
+
88
+ var noop = function(){
89
+ return this;
90
+ }
91
+
92
+ if(element){
93
+ this.on = function(action, func){
94
+ try {
95
+ // .on() supports the following actions: loaded, ready or click, interact
96
+ var validActions = ['loaded', 'ready', 'click', 'interact'];
97
+ if(validActions.indexOf(action) === -1){
98
+ throw('Not a valid action:', action);
99
+ }
100
+ if(typeof func !== 'function'){
101
+ throw('Not a valid function:', func);
102
+ }
103
+ onFunctions[action] = func;
104
+ listen();
105
+ } catch(e){
106
+ window.console && window.console.error(e);
107
+ }
108
+ return this;
109
+ };
110
+ this.activate = function(target){
111
+ send({action:'activate', target:target});
112
+ return this;
113
+ };
114
+ this.wait = function(){
115
+ send({action:'wait'});
116
+ return this;
117
+ };
118
+ this.resume = function(){
119
+ send({action:'resume'});
120
+ return this;
121
+ };
122
+ this.element = function(){
123
+ return element;
124
+ };
125
+ this.getDataStore = function(){
126
+ var callback, settings;
127
+ if(arguments.length === 2){
128
+ callback = arguments[1];
129
+ settings = arguments[0];
130
+ } else {
131
+ callback = arguments[0];
132
+ settings = {'records': false};
133
+ }
134
+ onFunctions['special'] = callback;
135
+ send({action:'getDataStore', settings: settings});
136
+ listen();
137
+ return this;
138
+ };
139
+ this.setDataStore = function(dataStore){
140
+ send({action:'setDataStore',dataStore: dataStore});
141
+ return this;
142
+ };
143
+ this.getDownload = function(format, callback){
144
+ onFunctions['getDownload'] = callback;
145
+ send({action:'getDownload', format: format});
146
+ listen();
147
+ return this;
148
+ };
149
+ } else {
150
+ this.on = noop;
151
+ this.activate = noop;
152
+ this.resume = noop;
153
+ this.element = noop;
154
+ this.getDataStore = noop;
155
+ this.getDownload = noop;
156
+ this.setDataStore = noop;
157
+ }
158
+ };
159
+
160
+ var forEach = function(items, callback){
161
+ if(!items || !callback){
162
+ return;
163
+ }
164
+ for (var i = 0; i < items.length; i++) {
165
+ var item = items[i];
166
+ callback.call(item, item, i);
167
+ };
168
+ };
169
+
170
+ var checkOrigin = function(elem){
171
+ var allow = false;
172
+ if(allowedOrigins.length){
173
+ // Allowed origin is set
174
+ forEach(allowedOrigins, function(origin){
175
+ if(elem && typeof elem.src === 'string' && elem.src.indexOf(origin) === 0){
176
+ // Allow
177
+ allow = true;
178
+ }
179
+ });
180
+ } else {
181
+ // Allowed origin is not set
182
+ allow = true;
183
+ }
184
+ return allow;
185
+ };
186
+
187
+ return {
188
+ oldBrowser: function(){
189
+ return oldBrowser;
190
+ },
191
+ select: function(d){
192
+ if(oldBrowser){
193
+ var elem = null;
194
+ } else {
195
+ var elem = (typeof d === 'string')?document.querySelector(d):d;
196
+ }
197
+ // Check origin
198
+ if(elem && checkOrigin(elem)){
199
+ return new widgetObject(elem);
200
+ } else {
201
+ return new widgetObject(null);
202
+ }
203
+ },
204
+ selectAll: function(d, loop){
205
+ if(!oldBrowser){
206
+ var elems = document.querySelectorAll(d);
207
+ forEach(elems, function(elem){
208
+ loop.call(new widgetObject(elem));
209
+ });
210
+ }
211
+ return null;
212
+ },
213
+ allowOrigin: function(origin){
214
+ if(typeof origin === 'string'){
215
+ allowedOrigins.push(origin);
216
+ }
217
+ return this;
218
+ }
219
+ }
220
+ })();
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pageflow-localfocus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joost Baaij
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-12-11 00:00:00.000000000 Z
11
+ date: 2017-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pageflow
@@ -104,19 +104,29 @@ files:
104
104
  - ".gitignore"
105
105
  - ".rspec"
106
106
  - ".travis.yml"
107
+ - CHANGELOG.md
108
+ - CODE_OF_CONDUCT.md
107
109
  - Gemfile
108
110
  - Gemfile.lock
111
+ - LICENSE
109
112
  - README.md
110
113
  - Rakefile
114
+ - app/assets/images/pageflow/localfocus/themes/default/page_type_pictograms/background_image/sprite.png
115
+ - app/assets/images/pageflow/localfocus/themes/default/page_type_pictograms/background_image/wide.png
116
+ - app/assets/images/pageflow/localfocus_pictogram_small.png
111
117
  - app/assets/javascripts/pageflow/localfocus.js
112
118
  - app/assets/javascripts/pageflow/localfocus/components.js
113
- - app/assets/javascripts/pageflow/localfocus/components/localfocus_iframe.jsx
119
+ - app/assets/javascripts/pageflow/localfocus/components/frame.jsx
114
120
  - app/assets/javascripts/pageflow/localfocus/components/page.jsx
115
121
  - app/assets/javascripts/pageflow/localfocus/editor.js
116
122
  - app/assets/javascripts/pageflow/localfocus/editor/templates/url_input.jst.ejs
117
123
  - app/assets/javascripts/pageflow/localfocus/editor/views/configuration_editor_view.js
118
124
  - app/assets/javascripts/pageflow/localfocus/editor/views/inputs/url_input_view.js
125
+ - app/assets/javascripts/pageflow/localfocus/widgets.js
126
+ - app/assets/javascripts/pageflow/localfocus/widgets/loading_spinner.js
127
+ - app/assets/stylesheets/pageflow/localfocus.scss
119
128
  - bin/console
129
+ - bin/rails
120
130
  - bin/setup
121
131
  - config/locales/en.yml
122
132
  - lib/pageflow/localfocus.rb
@@ -124,8 +134,10 @@ files:
124
134
  - lib/pageflow/localfocus/plugin.rb
125
135
  - lib/pageflow/localfocus/version.rb
126
136
  - pageflow-localfocus.gemspec
137
+ - vendor/assets/javascripts/localfocusapi.js
127
138
  homepage: https://github.com/scrollytelling/pageflow-localfocus
128
- licenses: []
139
+ licenses:
140
+ - MIT
129
141
  metadata: {}
130
142
  post_install_message:
131
143
  rdoc_options: []
@@ -1,22 +0,0 @@
1
- (function() {
2
- class LocalfocusIframe extends React.Component {
3
- render() {
4
- return (
5
- <iframe
6
- className="localfocusvisual"
7
- scrolling="no"
8
- frameborder="0"
9
- style="width:100%;height:550px;overflow:hidden"
10
- ref={iframe => this.iframe = iframe}
11
- src="https://localfocus2.appspot.com/551a9626918b3?api=1">
12
- </iframe>
13
- )
14
- }
15
- }
16
-
17
- const {connectInPage, combine} = pageflow.react;
18
-
19
- pageflow.localfocus.LocalfocusIframe = connectInPage(combine({
20
-
21
- }))(LocalfocusIframe);
22
- }());