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.
- checksums.yaml +4 -4
- data/.rspec +0 -2
- data/CHANGELOG.md +23 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile.lock +9 -5
- data/LICENSE +21 -0
- data/README.md +58 -3
- data/app/assets/images/pageflow/localfocus/themes/default/page_type_pictograms/background_image/sprite.png +0 -0
- data/app/assets/images/pageflow/localfocus/themes/default/page_type_pictograms/background_image/wide.png +0 -0
- data/app/assets/images/pageflow/localfocus_pictogram_small.png +0 -0
- data/app/assets/javascripts/pageflow/localfocus.js +1 -1
- data/app/assets/javascripts/pageflow/localfocus/components.js +1 -1
- data/app/assets/javascripts/pageflow/localfocus/components/frame.jsx +26 -0
- data/app/assets/javascripts/pageflow/localfocus/components/page.jsx +16 -7
- data/app/assets/javascripts/pageflow/localfocus/editor/templates/url_input.jst.ejs +5 -8
- data/app/assets/javascripts/pageflow/localfocus/editor/views/configuration_editor_view.js +15 -7
- data/app/assets/javascripts/pageflow/localfocus/editor/views/inputs/url_input_view.js +24 -26
- data/app/assets/javascripts/pageflow/localfocus/widgets.js +2 -0
- data/app/assets/javascripts/pageflow/localfocus/widgets/loading_spinner.js +27 -0
- data/app/assets/stylesheets/pageflow/localfocus.scss +7 -0
- data/bin/rails +14 -0
- data/config/locales/en.yml +39 -4
- data/lib/pageflow/localfocus.rb +1 -1
- data/lib/pageflow/localfocus/engine.rb +4 -0
- data/lib/pageflow/localfocus/plugin.rb +3 -1
- data/lib/pageflow/localfocus/version.rb +1 -1
- data/pageflow-localfocus.gemspec +1 -0
- data/vendor/assets/javascripts/localfocusapi.js +220 -0
- metadata +16 -4
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 669a2ff3409e820dc66cd1c716c7930fa26cf035
|
4
|
+
data.tar.gz: a3bb15be212d688eb5934be3e4e84574552f7f9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 123025b2b708f4086f5335b6bd5b5a0dd842a10bc43748cd1ca498b72ddb18bd981c9d52520ea3378e49aa769f873166a93fcf3441533d5ac2602484b4bc4e70
|
7
|
+
data.tar.gz: 42405d5a3d1608cb6561037f59aea3a0d10c128c1f4318c13a4e1be87072178c6204f68fef2acb4a39ebd7b2be5641c6ef710d56b2996f6177c8fc10efee97e2
|
data/.rspec
CHANGED
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
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -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
|
-
#
|
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
|
-
|
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
|
-
##
|
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
|
Binary file
|
Binary file
|
Binary file
|
@@ -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
|
-
|
4
|
+
MediaPageBackground, PageBackgroundImage, PageShadow,
|
5
5
|
PageContent, PageHeader, PageText
|
6
6
|
} = pageflow.react.components;
|
7
7
|
|
8
8
|
const {
|
9
|
-
|
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
|
-
<
|
17
|
-
</PageBackground>
|
20
|
+
<MediaPageBackground page={this.props.page} />
|
18
21
|
|
19
22
|
<PageContent>
|
20
|
-
<
|
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
|
-
<
|
12
|
-
|
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.
|
4
|
+
this.input('text', pageflow.TextAreaInputView);
|
5
|
+
this.input('text_position', pageflow.SelectInputView, {values: pageflow.Page.textPositions});
|
5
6
|
});
|
6
7
|
|
7
|
-
this.tab('
|
8
|
-
this.input('
|
9
|
-
|
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
|
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/
|
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/
|
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
|
-
|
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
|
-
|
22
|
-
|
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
|
-
|
37
|
-
|
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.
|
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,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
|
+
}
|
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'
|
data/config/locales/en.yml
CHANGED
@@ -1,10 +1,45 @@
|
|
1
1
|
en:
|
2
2
|
pageflow:
|
3
3
|
localfocus:
|
4
|
-
|
5
|
-
|
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:
|
10
|
-
text:
|
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
|
data/lib/pageflow/localfocus.rb
CHANGED
@@ -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.
|
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
|
data/pageflow-localfocus.gemspec
CHANGED
@@ -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:
|
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
|
+
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/
|
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
|
-
}());
|