Compare commits
14 Commits
feature/co
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
f233284e0c | ||
|
4f9dad26a4 | ||
|
c05989af61 | ||
|
31317a355b | ||
|
3fcb819881 | ||
|
e14af79691 | ||
|
9f2b6236a6 | ||
|
bc083c38c8 | ||
|
7eafdcab0e | ||
|
155f58500e | ||
|
86a4533435 | ||
|
02f43cea80 | ||
|
f82107ce21 | ||
|
602e90be57 |
46
.github/workflows/ruby.yml
vendored
46
.github/workflows/ruby.yml
vendored
@ -1,46 +0,0 @@
|
||||
name: Ruby
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, develop ]
|
||||
pull_request:
|
||||
branches: "*"
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- rails-version: "5.2.0"
|
||||
- rails-version: "6.0.0"
|
||||
- rails-version: "6.1.0"
|
||||
|
||||
env:
|
||||
RAILS_VERSION: ${{ matrix.rails-version }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
- name: Generate lockfile
|
||||
run: bundle lock
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: bundle-${{ hashFiles('Gemfile.lock') }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
bundle config path vendor/bundle
|
||||
gem install bundler --conservative
|
||||
bundle check || bundle install
|
||||
- name: Install JS dependencies
|
||||
run: yarn
|
||||
- name: Create database
|
||||
run: bundle exec rake db:create db:migrate
|
||||
- name: Run tests
|
||||
run: bundle exec rake test
|
@ -1 +1 @@
|
||||
abraham
|
||||
walter
|
||||
|
@ -1 +1 @@
|
||||
2.5.3
|
||||
2.6.5
|
||||
|
14
.travis.yml
14
.travis.yml
@ -1,14 +0,0 @@
|
||||
language: ruby
|
||||
|
||||
env:
|
||||
- 'RAILS_VERSION=5.2.0'
|
||||
- 'RAILS_VERSION=6.0.0'
|
||||
- 'RAILS_VERSION=6.1.0'
|
||||
|
||||
before_script:
|
||||
- 'yarn'
|
||||
- 'bundle install'
|
||||
- 'RAILS_ENV=test bundle exec rake db:create'
|
||||
- 'RAILS_ENV=test bundle exec rake db:migrate'
|
||||
|
||||
script: 'RAILS_ENV=test bundle exec rake test'
|
2
Gemfile
2
Gemfile
@ -19,7 +19,7 @@ rails = case rails_version
|
||||
end
|
||||
gem 'rails', rails
|
||||
|
||||
# Declare your gem's dependencies in abraham.gemspec.
|
||||
# Declare your gem's dependencies in walter.gemspec.
|
||||
# Bundler will treat runtime dependencies like base dependencies, and
|
||||
# development dependencies will be added by default to the :development group.
|
||||
gemspec
|
||||
|
163
README.md
163
README.md
@ -1,30 +1,34 @@
|
||||
# Abraham
|
||||
# Walter
|
||||
|
||||
[](https://travis-ci.com/actmd/abraham)
|
||||
[](https://travis-ci.com/actmd/walter)
|
||||
|
||||
_Guide your users in the one true path._
|
||||
|
||||

|
||||
|
||||
Abraham makes it easy to show guided tours to users of your Rails application. When Abraham shows a tour, it keeps track of whether the user has completed it (so it doesn't get shown again) or dismissed it for later (so it reappears in a future user session).
|
||||
<p align="center">
|
||||
<i>Product tours like a badass.</i>
|
||||
<br/>
|
||||
<img src="https://img.icons8.com/doodle/240/000000/walter-white.png"/>
|
||||
<br/>
|
||||
<a style='font-size: 12px;' href="https://icons8.com/icon/5iWNvQRbAKx9/walter-white">Walter White icon by Icons8</a>
|
||||
</p>
|
||||
Walter makes it easy to show guided tours to users of your Rails application. When Walter shows a tour, it keeps track of whether the user has completed it (so it doesn't get shown again) or dismissed it for later (so it reappears in a future user session).
|
||||
|
||||
* Define tour content with simple YAML files, in any/many languages.
|
||||
* Organize tours by controller and action.
|
||||
* Trigger tours automatically on page load or manually via JavaScript method.
|
||||
* Built with the [Shepherd JS](https://shepherdjs.dev/) library. Plays nicely with Turbolinks.
|
||||
* Ships with two basic CSS themes (default & dark) — or write your own
|
||||
* Show video/html content in your
|
||||
|
||||
## Requirements
|
||||
|
||||
* Abraham needs to know the current user to track tour views, e.g. `current_user` from Devise.
|
||||
* Abraham is tested on Rails 5.2, 6.0, and 6.1
|
||||
* Walter needs to know the current user to track tour views, e.g. `current_user` from Devise.
|
||||
* Walter is tested on Rails 5.2, 6.0, and 6.1
|
||||
|
||||
## Installation
|
||||
|
||||
Add `abraham` to your Gemfile:
|
||||
Add `walter` to your Gemfile:
|
||||
|
||||
```
|
||||
gem 'abraham'
|
||||
gem 'walter'
|
||||
|
||||
```
|
||||
|
||||
@ -32,7 +36,7 @@ Install the gem and run the installer:
|
||||
|
||||
```
|
||||
$ bundle install
|
||||
$ rails generate abraham:install
|
||||
$ rails generate walter:install
|
||||
$ rails db:migrate
|
||||
```
|
||||
|
||||
@ -42,24 +46,24 @@ Install the JavaScript dependencies:
|
||||
$ yarn add js-cookie@^2.2.0 shepherd.js@^6.0.0-beta
|
||||
```
|
||||
|
||||
Require `abraham` in `app/assets/javascripts/application.js`
|
||||
Require `walter` in `app/assets/javascripts/application.js`
|
||||
|
||||
```
|
||||
//= require abraham
|
||||
//= require walter
|
||||
```
|
||||
|
||||
Require a CSS theme in `app/assets/stylesheets/application.scss`
|
||||
|
||||
```
|
||||
*= require abraham/theme-default
|
||||
*= require walter/theme-default
|
||||
```
|
||||
|
||||
Abraham provides the following themes:
|
||||
Walter provides the following themes:
|
||||
|
||||
- `theme-default`
|
||||
- `theme-dark`
|
||||
|
||||
Update `config/abraham.yml` if you choose a different theme:
|
||||
Update `config/walter.yml` if you choose a different theme:
|
||||
|
||||
```
|
||||
defaults: &defaults
|
||||
@ -68,22 +72,25 @@ defaults: &defaults
|
||||
|
||||
You can also [write your own Shepherd theme](https://shepherdjs.dev/docs/tutorial-03-styling.html) based on Shepherd's [default CSS](https://github.com/shipshapecode/shepherd/releases/download/v6.0.0-beta.1/shepherd.css).
|
||||
|
||||
Tell Abraham where to insert its generated JavaScript in `app/views/layouts/application.html.erb`, just before the closing `body` tag:
|
||||
Tell Walter where to insert its generated JavaScript in `app/views/layouts/application.html.erb`, just before the closing `body` tag:
|
||||
|
||||
```erb
|
||||
<%= abraham_tour %>
|
||||
<%= walter_tour %>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Defining your tours
|
||||
|
||||
Define your tours in the `config/tours` directory corresponding to the views defined in your application. Its directory structure mirrors your application's controllers, and the tour files mirror your actions/views.
|
||||
Define your tours in the `app/tours` directory corresponding to the views defined in your application. Its directory structure mirrors your application's controllers, and the tour files mirror your actions/views. (As of version 2.4.0, Walter respects controllers organized into modules.)
|
||||
|
||||
```
|
||||
config/
|
||||
app/
|
||||
└── tours/
|
||||
└── blog/
|
||||
├── admin/
|
||||
│ └── articles/
|
||||
│ └── edit.en.yml
|
||||
├── blog/
|
||||
│ ├── show.en.yml
|
||||
│ └── show.es.yml
|
||||
└── articles/
|
||||
@ -122,10 +129,10 @@ intro:
|
||||
placement: "bottom"
|
||||
```
|
||||
|
||||
Abraham takes care of which buttons should appear with each step:
|
||||
Walter takes care of which buttons should appear with each step:
|
||||
|
||||
* "Later" and "Continue" buttons on the first step
|
||||
* "Exit" and "Next" buttons on intermediate steps
|
||||
* "Exit", "Back" and "Continue" buttons on intermediate steps
|
||||
* "Done" button on the last step
|
||||
|
||||
When you specify an `attachTo` element, use the `placement` option to choose where the callout should appear relative to that element:
|
||||
@ -140,14 +147,15 @@ When you specify an `attachTo` element, use the `placement` option to choose whe
|
||||
* `top left`
|
||||
* `top right`
|
||||
|
||||
Abraham tries to be helpful when your tour steps attach to page elements that are missing:
|
||||
Walter tries to be helpful when your tour steps attach to page elements that are missing:
|
||||
|
||||
* If your first step is attached to a particular element, and that element is not present on the page, the tour won't start. ([#28](https://github.com/actmd/abraham/issues/28))
|
||||
* If your tour has an intermediate step attached to a missing element, Abraham will skip that step and automatically show the next. ([#6](https://github.com/actmd/abraham/issues/6))
|
||||
* If your first step is attached to a particular element, and that element is not present on the page, the tour won't start. ([#28](https://github.com/actmd/walter/issues/28))
|
||||
* If your tour has an intermediate step attached to a missing element, Walter will skip that step and automatically show the next. ([#6](https://github.com/actmd/walter/issues/6))
|
||||
|
||||
### Automatic vs. manual tours
|
||||
|
||||
By default, Abraham will automatically start a tour that the current user hasn't seen yet. You can instead define a tour to be triggered manually using the `trigger` option:
|
||||
By default, Walter will automatically start a tour that the current user hasn't seen yet.
|
||||
You can instead define a tour to be triggered manually using the `trigger` option:
|
||||
|
||||
```yml
|
||||
walkthrough:
|
||||
@ -157,14 +165,14 @@ walkthrough:
|
||||
text: "This walkthrough will show you how to..."
|
||||
```
|
||||
|
||||
This tour will not start automatically; instead, use the `Abraham.startTour` method with the tour name:
|
||||
This tour will not start automatically; instead, use the `Walter.startTour` method with the tour name:
|
||||
|
||||
```
|
||||
<button id="startTour">Start tour</button>
|
||||
|
||||
<script>
|
||||
document.querySelector("#startTour").addEventListener("click", function() {
|
||||
Abraham.startTour("walkthrough"));
|
||||
Walter.startTour("walkthrough"));
|
||||
});
|
||||
</script>
|
||||
```
|
||||
@ -173,106 +181,19 @@ This tour will not start automatically; instead, use the `Abraham.startTour` met
|
||||
|
||||
```
|
||||
<script>
|
||||
$("#startTour").on("click", function() { Abraham.startTour('walkthrough'); })
|
||||
$("#startTour").on("click", function() { Walter.startTour('walkthrough'); })
|
||||
</script>
|
||||
```
|
||||
|
||||
### Testing your tours
|
||||
|
||||
Abraham loads tour definitions once when you start your server. Restart your server to see tour changes.
|
||||
Walter loads tour definitions once when you start your server. Restart your server to see tour changes.
|
||||
|
||||
If you'd like to run JavaScript integrations tests without the Abraham tours getting in the way, clear the Abraham configuration in your test helper, e.g.
|
||||
If you'd like to run JavaScript integrations tests without the Walter tours getting in the way, clear the Walter configuration in your test helper, e.g.
|
||||
|
||||
```
|
||||
Rails.application.configure do
|
||||
config.abraham.tours = {}
|
||||
config.walter.tours = {}
|
||||
end
|
||||
```
|
||||
|
||||
## Full example
|
||||
|
||||
We provide a [small example app](https://github.com/actmd/abraham-example) that implements Abraham, so you can see it in action.
|
||||
|
||||
## Upgrading from version 1
|
||||
|
||||
Abraham v1 was built using Shepherd 1.8, v2 now uses Shepherd 6 – quite a jump, yes.
|
||||
|
||||
If you were using Abraham v1, you'll want to take the following steps to upgrade:
|
||||
|
||||
1. Update your gem to the latest version
|
||||
1. Fix your yarn dependencies to use the right versions
|
||||
1. Shepherd no longer provides a set of themes. Abraham maintains two of the legacy themes: default and dark. You'll want to choose one of those or migrate your theme to the new Shepherd structure.
|
||||
1. Abraham now exposes the entire Shepherd configuration object, so your `abraham.yml` file should now fully define the `tour_options` value instead of `default_theme`
|
||||
1. There's been a slight change to `initializers/abraham.rb`. Replace yours with [the latest](https://github.com/actmd/abraham/blob/master/lib/generators/abraham/templates/initializer.rb).
|
||||
|
||||
If you have any trouble at all, please [submit an issue](https://github.com/actmd/abraham/issues) for assistance!
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome!
|
||||
|
||||
Create a feature branch (using git-flow) and submit as a pull request (with a base branch of `develop`).
|
||||
|
||||
Everyone interacting in Abraham's codebase, issue tracker, etc. is expected to follow the [Contributor Covenent Code of Conduct](https://www.contributor-covenant.org/version/1/4/code-of-conduct).
|
||||
|
||||
### Getting started with the source code
|
||||
|
||||
Abraham uses `rvm` with a gemset to ensure the appropriate version of Ruby and its dependencies. Make sure that's installed before you get started.
|
||||
|
||||
```
|
||||
~ git clone git@github.com:actmd/abraham.git
|
||||
Cloning into 'abraham'...
|
||||
~ cd abraham
|
||||
ruby-2.5.3 - #gemset created /Users/jon/.rvm/gems/ruby-2.5.3@abraham
|
||||
ruby-2.5.3 - #generating abraham wrappers - please wait
|
||||
~ bundle install
|
||||
Bundle complete! 13 Gemfile dependencies, 73 gems now installed.
|
||||
Use `bundle info [gemname]` to see where a bundled gem is installed.
|
||||
~ yarn install
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
#### Testing locally
|
||||
|
||||
This Rails engine contains a test app called `dummy` with controller and system tests. They'll all get run with `rails t`.
|
||||
|
||||
Please note that if you change anything in the `lib/generators` folder (i.e. configuration, intializer, migration) you'll need to migrate the `dummy` app accordingly.
|
||||
|
||||
Final testing should be done in a standalone Rails app, following the README instructions.
|
||||
|
||||
To install the `abraham` gem with a local path:
|
||||
|
||||
```
|
||||
gem 'abraham', path: '~/Workspace/abraham'
|
||||
```
|
||||
|
||||
#### Automated testing
|
||||
|
||||
We use TravisCI to automatically test this engine with Rails 5.2, 6.0, and 6.1. For test history, venture over to [TravisCI](https://travis-ci.com/actmd/abraham).
|
||||
|
||||
### Releasing
|
||||
|
||||
Create a git-flow release:
|
||||
|
||||
```
|
||||
$ git flow release start VERSION_NUMBER
|
||||
```
|
||||
|
||||
Edit `lib/abraham/version.rb` and increase the version number.
|
||||
|
||||
Build the gem and push to Rubygems:
|
||||
|
||||
```
|
||||
$ rake build
|
||||
$ gem push pkg/abraham-VERSION_NUMBER.gem
|
||||
```
|
||||
|
||||
Finish the git-flow release and push to GitHub:
|
||||
|
||||
```
|
||||
$ git flow release finish
|
||||
$ git push origin develop
|
||||
$ git push origin master
|
||||
$ git push --tags
|
||||
```
|
||||
|
2
Rakefile
2
Rakefile
@ -10,7 +10,7 @@ require "rdoc/task"
|
||||
|
||||
RDoc::Task.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = "rdoc"
|
||||
rdoc.title = "Abraham"
|
||||
rdoc.title = "Walter"
|
||||
rdoc.options << "--line-numbers"
|
||||
rdoc.rdoc_files.include("README.md")
|
||||
rdoc.rdoc_files.include("lib/**/*.rb")
|
||||
|
@ -1,28 +0,0 @@
|
||||
//= require js-cookie/src/js.cookie
|
||||
//= require shepherd.js/dist/js/shepherd
|
||||
|
||||
var Abraham = new Object();
|
||||
|
||||
Abraham.tours = {};
|
||||
Abraham.incompleteTours = [];
|
||||
Abraham.startTour = function(tourName) {
|
||||
if (!Shepherd.activeTour) {
|
||||
Abraham.tours[tourName].start();
|
||||
}
|
||||
};
|
||||
Abraham.startNextIncompleteTour = function() {
|
||||
if (Abraham.incompleteTours.length) {
|
||||
Abraham.tours[Abraham.incompleteTours[0]].checkAndStart();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("DOMContentLoaded", Abraham.startNextIncompleteTour);
|
||||
document.addEventListener("turbolinks:load", Abraham.startNextIncompleteTour);
|
||||
|
||||
document.addEventListener('turbolinks:before-cache', function() {
|
||||
// Remove visible product tours
|
||||
document.querySelectorAll(".shepherd-element").forEach(function(el) { el.remove() });
|
||||
// Clear Abraham data
|
||||
Abraham.tours = {};
|
||||
Abraham.incompleteTours = [];
|
||||
});
|
28
app/assets/javascripts/walter/index.js
Normal file
28
app/assets/javascripts/walter/index.js
Normal file
@ -0,0 +1,28 @@
|
||||
//= require js-cookie/src/js.cookie
|
||||
//= require shepherd.js/dist/js/shepherd
|
||||
|
||||
var Walter = new Object();
|
||||
|
||||
Walter.tours = {};
|
||||
Walter.incompleteTours = [];
|
||||
Walter.startTour = function(tourName) {
|
||||
if (!Shepherd.activeTour) {
|
||||
setTimeout(function(){Walter.tours[tourName].start()}, 300);
|
||||
}
|
||||
};
|
||||
Walter.startNextIncompleteTour = function() {
|
||||
if (Walter.incompleteTours.length) {
|
||||
Walter.tours[Walter.incompleteTours[0]].checkAndStart();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("DOMContentLoaded", Walter.startNextIncompleteTour);
|
||||
document.addEventListener("turbolinks:load", Walter.startNextIncompleteTour);
|
||||
|
||||
document.addEventListener('turbolinks:before-cache', function() {
|
||||
// Remove visible product tours
|
||||
document.querySelectorAll(".shepherd-element").forEach(function(el) { el.remove() });
|
||||
// Clear Walter data
|
||||
Walter.tours = {};
|
||||
Walter.incompleteTours = [];
|
||||
});
|
@ -79,7 +79,7 @@
|
||||
border-top-right-radius: 5px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 0.5rem 1rem 0;
|
||||
padding: 0.5rem 0rem 0;
|
||||
}
|
||||
|
||||
.shepherd-has-title .shepherd-content .shepherd-header {
|
||||
@ -108,7 +108,7 @@
|
||||
.shepherd-element {
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, .2);
|
||||
max-width: 400px;
|
||||
//max-width: 600px;
|
||||
outline: none;
|
||||
z-index: 9999;
|
||||
line-height: 1.2;
|
117
app/assets/stylesheets/walter/shepherd.css
Normal file
117
app/assets/stylesheets/walter/shepherd.css
Normal file
@ -0,0 +1,117 @@
|
||||
.shepherd-button:hover {
|
||||
background: #16202D;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.shepherd-button.shepherd-button-secondary {
|
||||
background: #CAD5D5;
|
||||
}
|
||||
|
||||
.shepherd-button.shepherd-button-secondary:hover {
|
||||
color: #CAD5D5;
|
||||
background: #16202D;
|
||||
}
|
||||
|
||||
.shepherd-cancel-icon {
|
||||
font-family: "GT Pressura", sans-serif;
|
||||
}
|
||||
|
||||
.shepherd-element {
|
||||
border: solid 4px #16202D;
|
||||
}
|
||||
|
||||
.shepherd-element,
|
||||
.shepherd-header,
|
||||
.shepherd-footer {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.shepherd-element .shepherd-arrow {
|
||||
border-width: 0;
|
||||
height: auto;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.shepherd-arrow::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.shepherd-element .shepherd-arrow:after {
|
||||
content: url('../assets/img/arrow.svg');
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.shepherd-element[data-popper-placement^='top'] .shepherd-arrow,
|
||||
.shepherd-element.shepherd-pinned-top .shepherd-arrow {
|
||||
bottom: -35px;
|
||||
}
|
||||
|
||||
.shepherd-element[data-popper-placement^='top'] .shepherd-arrow:after,
|
||||
.shepherd-element.shepherd-pinned-top .shepherd-arrow:after {
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
||||
.shepherd-element[data-popper-placement^='bottom'] .shepherd-arrow {
|
||||
top: -35px;
|
||||
}
|
||||
|
||||
.shepherd-element[data-popper-placement^='bottom'] .shepherd-arrow:after {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.shepherd-element[data-popper-placement^='left'] .shepherd-arrow,
|
||||
.shepherd-element.shepherd-pinned-left .shepherd-arrow {
|
||||
right: -35px;
|
||||
}
|
||||
|
||||
.shepherd-element[data-popper-placement^='left'] .shepherd-arrow:after,
|
||||
.shepherd-element.shepherd-pinned-left .shepherd-arrow:after {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.shepherd-element[data-popper-placement^='right'] .shepherd-arrow,
|
||||
.shepherd-element.shepherd-pinned-right .shepherd-arrow {
|
||||
left: -35px;
|
||||
}
|
||||
|
||||
.shepherd-footer {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.shepherd-footer button:not(:last-of-type) {
|
||||
border-right: solid 4px #16202D;
|
||||
}
|
||||
|
||||
.shepherd-has-title .shepherd-content .shepherd-cancel-icon {
|
||||
margin-top: -7px;
|
||||
}
|
||||
|
||||
.shepherd-has-title .shepherd-content .shepherd-header {
|
||||
background: transparent;
|
||||
font-family: "GT Pressura", sans-serif;
|
||||
padding-bottom: 0;
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
.shepherd-has-title .shepherd-content .shepherd-header .shepherd-title {
|
||||
font-size: 1.2rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.shepherd-text {
|
||||
font-size: 1.2rem;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.shepherd-text a, .shepherd-text a:visited,
|
||||
.shepherd-text a:active {
|
||||
border-bottom: 1px dotted;
|
||||
border-bottom-color: rgba(0, 0, 0, 0.75);
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.shepherd-text a:hover, .shepherd-text a:visited:hover,
|
||||
.shepherd-text a:active:hover {
|
||||
border-bottom-style: solid;
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class AbrahamHistoriesController < ApplicationController
|
||||
def create
|
||||
@abraham_history = AbrahamHistory.new(abraham_history_params)
|
||||
@abraham_history.creator_id = current_user.id
|
||||
respond_to do |format|
|
||||
if @abraham_history.save
|
||||
format.json { render json: @abraham_history, status: :created }
|
||||
else
|
||||
format.json { render json: @abraham_history.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def abraham_history_params
|
||||
params.require(:abraham_history).permit(:controller_name, :action_name, :tour_name)
|
||||
end
|
||||
end
|
21
app/controllers/walter_histories_controller.rb
Normal file
21
app/controllers/walter_histories_controller.rb
Normal file
@ -0,0 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class WalterHistoriesController < ApplicationController
|
||||
def create
|
||||
@walter_history = WalterHistory.new(walter_history_params)
|
||||
@walter_history.creator_id = current_user.id
|
||||
respond_to do |format|
|
||||
if @walter_history.save
|
||||
format.json { render json: @walter_history, status: :created }
|
||||
else
|
||||
format.json { render json: @walter_history.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def walter_history_params
|
||||
params.require(:walter_history).permit(:controller_name, :action_name, :tour_name)
|
||||
end
|
||||
end
|
@ -1,17 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module AbrahamHelper
|
||||
def abraham_tour
|
||||
module WalterHelper
|
||||
def walter_tour
|
||||
# Do we have tours for this controller/action in the user's locale?
|
||||
tours = Rails.configuration.abraham.tours["#{controller_name}.#{action_name}.#{I18n.locale}"]
|
||||
tours = Walter.tours["#{controller_path}.#{action_name}.#{I18n.locale}"]
|
||||
# Otherwise, default to the default locale
|
||||
tours ||= Rails.configuration.abraham.tours["#{controller_name}.#{action_name}.#{I18n.default_locale}"]
|
||||
tours ||= Walter.tours["#{controller_path}.#{action_name}.#{I18n.default_locale}"]
|
||||
|
||||
if tours
|
||||
# Have any automatic tours been completed already?
|
||||
completed = AbrahamHistory.where(
|
||||
completed = WalterHistory.where(
|
||||
creator_id: current_user.id,
|
||||
controller_name: controller_name,
|
||||
controller_name: controller_path,
|
||||
action_name: action_name
|
||||
)
|
||||
|
||||
@ -21,19 +21,19 @@ module AbrahamHelper
|
||||
tour_html = ''
|
||||
|
||||
tour_keys.each do |key|
|
||||
tour_html += render(partial: "application/abraham",
|
||||
tour_html += (render(partial: "application/shepherd",
|
||||
locals: { tour_name: key,
|
||||
tour_completed: tour_keys_completed.include?(key),
|
||||
trigger: tours[key]["trigger"],
|
||||
steps: tours[key]["steps"] })
|
||||
tour_delay: tours[key]['delay']||500,
|
||||
steps: tours[key]["steps"] }))
|
||||
end
|
||||
|
||||
tour_html.html_safe
|
||||
end
|
||||
end
|
||||
|
||||
def abraham_cookie_prefix
|
||||
"abraham-#{fetch_application_name.to_s.underscore}-#{current_user.id}-#{controller_name}-#{action_name}"
|
||||
def walter_cookie_prefix
|
||||
"walter-#{fetch_application_name.to_s.underscore}-#{current_user.id}-#{controller_path}-#{action_name}"
|
||||
end
|
||||
|
||||
def fetch_application_name
|
||||
@ -44,8 +44,7 @@ module AbrahamHelper
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def abraham_domain
|
||||
def walter_domain
|
||||
request.host
|
||||
end
|
||||
end
|
@ -1,4 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class AbrahamHistory < ActiveRecord::Base
|
||||
end
|
4
app/models/walter_history.rb
Normal file
4
app/models/walter_history.rb
Normal file
@ -0,0 +1,4 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class WalterHistory < ActiveRecord::Base
|
||||
end
|
@ -1,75 +0,0 @@
|
||||
<script>
|
||||
Abraham.tours["<%= tour_name %>"] = new Shepherd.Tour(<%= Rails.configuration.abraham.tour_options.html_safe unless Rails.configuration.abraham.tour_options.nil? %>);
|
||||
|
||||
<% if trigger != 'manual' %>
|
||||
Abraham.tours["<%= tour_name %>"].on("complete", function() {
|
||||
// Make AJAX call to save history of tour completion
|
||||
return fetch("/abraham_histories/", {
|
||||
method: "POST",
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
authenticity_token: '<%= form_authenticity_token %>',
|
||||
controller_name: '<%= controller_name %>',
|
||||
action_name: '<%= action_name %>',
|
||||
tour_name: '<%= tour_name %>'
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
Abraham.tours["<%= tour_name %>"].on("cancel", function() {
|
||||
Cookies.set('<%= abraham_cookie_prefix %>-<%= tour_name %>', 'later', { domain: '<%= abraham_domain %>' });
|
||||
});
|
||||
<% end %>
|
||||
|
||||
<% steps.each_with_index do |(key, step), index| %>
|
||||
Abraham.tours["<%= tour_name %>"].addStep({
|
||||
id: 'step-<%= key %>',
|
||||
<% if step.key?('title') %>
|
||||
title: "<%= step['title'] %>",
|
||||
<% end %>
|
||||
text: "<%= step['text'] %>",
|
||||
<% if step.key?('attachTo') %>
|
||||
attachTo: { element: "<%= step['attachTo']['element'] %>", on: "<%= step['attachTo']['placement'] %>" },
|
||||
showOn: function() {
|
||||
// Only display this step if its selector is present
|
||||
return document.querySelector("<%= step['attachTo']['element'] %>") ? true : false
|
||||
},
|
||||
<% end %>
|
||||
buttons: [
|
||||
<% if index == steps.size - 1 %>
|
||||
{ text: '<%= t('abraham.done') %>', action: Abraham.tours["<%= tour_name %>"].complete }
|
||||
<% else %>
|
||||
<% if index == 0 %>
|
||||
{ text: '<%= t('abraham.later') %>', action: Abraham.tours["<%= tour_name %>"].cancel, classes: 'shepherd-button-secondary' },
|
||||
{ text: '<%= t('abraham.continue') %>', action: Abraham.tours["<%= tour_name %>"].next }
|
||||
<% else %>
|
||||
{ text: '<%= t('abraham.exit') %>', action: Abraham.tours["<%= tour_name %>"].cancel, classes: 'shepherd-button-secondary' },
|
||||
{ text: '<%= t('abraham.next') %>', action: Abraham.tours["<%= tour_name %>"].next }
|
||||
<% end %>
|
||||
<% end %>
|
||||
]
|
||||
});
|
||||
<% end %>
|
||||
|
||||
<% if trigger != "manual" %>
|
||||
Abraham.tours["<%= tour_name %>"].checkAndStart = function (start) {
|
||||
return function () {
|
||||
// Don't start the tour if the user dismissed it once this session
|
||||
var tourMayStart = !Cookies.get('<%= abraham_cookie_prefix %>-<%= tour_name %>', {domain: '<%= abraham_domain %>'});
|
||||
<% if steps.first[1]['attachTo'] %>
|
||||
// Don't start the tour if the first step's element is missing
|
||||
tourMayStart = tourMayStart && document.querySelector("<%= steps.first[1]['attachTo']['element'] %>");
|
||||
<% end %>
|
||||
|
||||
if (tourMayStart) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
}(Abraham.tours["<%= tour_name %>"].start)
|
||||
|
||||
<% if !tour_completed %>
|
||||
Abraham.incompleteTours.push("<%= tour_name %>");
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
</script>
|
77
app/views/application/_shepherd.html.erb
Normal file
77
app/views/application/_shepherd.html.erb
Normal file
@ -0,0 +1,77 @@
|
||||
<script>
|
||||
Walter.tours["<%= tour_name %>"] = new Shepherd.Tour(<%= Rails.configuration.walter.tour_options.html_safe unless Rails.configuration.walter.tour_options.nil? %>);
|
||||
|
||||
<% if trigger != 'manual' %>
|
||||
Walter.tours["<%= tour_name %>"].on("complete", function() {
|
||||
// Make AJAX call to save history of tour completion
|
||||
return fetch("/walter_histories/", {
|
||||
method: "POST",
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
authenticity_token: '<%= form_authenticity_token %>',
|
||||
controller_name: '<%= controller_path %>',
|
||||
action_name: '<%= action_name %>',
|
||||
tour_name: '<%= tour_name %>'
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
Walter.tours["<%= tour_name %>"].on("cancel", function() {
|
||||
Cookies.set('<%= walter_cookie_prefix %>-<%= tour_name %>', 'later', { domain: '<%= walter_domain %>' });
|
||||
});
|
||||
<% end %>
|
||||
|
||||
<% steps.each_with_index do |(key, step), index| %>
|
||||
Walter.tours["<%= tour_name %>"].addStep({
|
||||
id: 'step-<%= key %>',
|
||||
<% if step.key?('title') %>
|
||||
title: "<%== step['title'] %>",
|
||||
<% end %>
|
||||
text: "<%== step['text'] %>",
|
||||
<% if step.key?('attachTo') %>
|
||||
attachTo: { element: "<%= step['attachTo']['element'] %>", on: "<%= step['attachTo']['placement'] %>" },
|
||||
showOn: function() {
|
||||
// Only display this step if its selector is present
|
||||
return document.querySelector("<%= step['attachTo']['element'] %>") ? true : false
|
||||
},
|
||||
<% end %>
|
||||
buttons: [
|
||||
<% if index == steps.size - 1 %>
|
||||
<% if steps.size > 1 %>
|
||||
{ text: '<%= t('walter.back') %>', action: Walter.tours["<%= tour_name %>"].back, classes: 'shepherd-button-secondary' },
|
||||
<% end %>
|
||||
{ text: '<%= t('walter.done') %>', action: Walter.tours["<%= tour_name %>"].complete },
|
||||
<% else %>
|
||||
<% if index == 0 %>
|
||||
{ text: '<%= t('walter.later') %>', action: Walter.tours["<%= tour_name %>"].cancel, classes: 'shepherd-button-secondary' },
|
||||
<% else %>
|
||||
{ text: '<%= t('walter.back') %>', action: Walter.tours["<%= tour_name %>"].back, classes: 'shepherd-button-secondary' },
|
||||
<% end %>
|
||||
{ text: '<%= t('walter.continue') %>', action: Walter.tours["<%= tour_name %>"].next },
|
||||
<% end %>
|
||||
]
|
||||
});
|
||||
<% end %>
|
||||
|
||||
<% if trigger != "manual" %>
|
||||
Walter.tours["<%= tour_name %>"].checkAndStart = function (start) {
|
||||
return function () {
|
||||
// Don't start the tour if the user dismissed it once this session
|
||||
var tourMayStart = !Cookies.get('<%= walter_cookie_prefix %>-<%= tour_name %>', {domain: '<%= walter_domain %>'});
|
||||
<% if steps.first[1]['attachTo'] %>
|
||||
// Don't start the tour if the first step's element is missing
|
||||
tourMayStart = tourMayStart && document.querySelector("<%= steps.first[1]['attachTo']['element'] %>");
|
||||
<% end %>
|
||||
|
||||
if (tourMayStart) {
|
||||
setTimeout(function(){start();}, <%= tour_delay %>); // need to delay this
|
||||
}
|
||||
}
|
||||
}(Walter.tours["<%= tour_name %>"].start)
|
||||
|
||||
<% if !tour_completed %>
|
||||
Walter.incompleteTours.push("<%= tour_name %>");
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
</script>
|
@ -5,7 +5,7 @@
|
||||
# installed from the root of your application.
|
||||
|
||||
ENGINE_ROOT = File.expand_path("..", __dir__)
|
||||
ENGINE_PATH = File.expand_path("../lib/abraham/engine", __dir__)
|
||||
ENGINE_PATH = File.expand_path("../lib/walter/engine", __dir__)
|
||||
|
||||
# Set up gems listed in the Gemfile.
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
||||
|
@ -1,7 +1,8 @@
|
||||
en:
|
||||
abraham:
|
||||
walter:
|
||||
later: "Later"
|
||||
continue: "Continue"
|
||||
exit: "Exit"
|
||||
done: "Done"
|
||||
next: "Next"
|
||||
back: "Back"
|
||||
|
@ -1,5 +1,5 @@
|
||||
es:
|
||||
abraham:
|
||||
walter:
|
||||
later: "Luego"
|
||||
continue: "Continuar"
|
||||
exit: "Dejar"
|
||||
|
@ -1,5 +1,5 @@
|
||||
fr:
|
||||
abraham:
|
||||
walter:
|
||||
later: "Plus tard"
|
||||
continue: "Continuer"
|
||||
exit: "Quitter"
|
||||
|
@ -1,5 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
Rails.application.routes.draw do
|
||||
resources :abraham_histories, only: :create
|
||||
resources :walter_histories, only: :create
|
||||
end
|
||||
|
@ -1,6 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abraham/engine"
|
||||
|
||||
module Abraham
|
||||
end
|
@ -1,5 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Abraham
|
||||
VERSION = "2.3.0.beta"
|
||||
end
|
@ -1,24 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
Rails.application.configure do
|
||||
tours = {}
|
||||
|
||||
if Rails.root.join('config/tours').exist?
|
||||
Dir[Rails.root.join('config/tours/*/')].each do |dir|
|
||||
Dir[dir + '*.yml'].each do |yml|
|
||||
path_parts = yml.split(File::SEPARATOR)
|
||||
controller = path_parts[path_parts.size - 2]
|
||||
file_parts = path_parts[path_parts.size - 1].split('.')
|
||||
action = file_parts[0]
|
||||
locale = file_parts[1]
|
||||
t = YAML.load_file(yml)
|
||||
tours["#{controller}.#{action}.#{locale}"] = t
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
abraham_config = Rails.application.config_for :abraham
|
||||
config.abraham = ActiveSupport::OrderedOptions.new
|
||||
config.abraham.tour_options = abraham_config[:tour_options]
|
||||
config.abraham.tours = tours
|
||||
end
|
@ -3,13 +3,14 @@
|
||||
require "rails/generators"
|
||||
require "rails/generators/active_record"
|
||||
|
||||
module Abraham
|
||||
module Walter
|
||||
module Generators
|
||||
class InstallGenerator < ActiveRecord::Generators::Base
|
||||
argument :name, type: :string, default: "random_name"
|
||||
|
||||
class_option :'skip-migration', type: :boolean, desc: "Don't generate a migration for the histories table"
|
||||
class_option :'skip-initializer', type: :boolean, desc: "Don't generate an initializer"
|
||||
class_option :'skip-config', type: :boolean, desc: "Don't generate a config file"
|
||||
|
||||
source_root File.expand_path(File.join(File.dirname(__FILE__), "templates"))
|
||||
|
||||
@ -17,14 +18,19 @@ module Abraham
|
||||
def copy_files
|
||||
return if options["skip-migration"]
|
||||
|
||||
migration_template "migration.rb", "db/migrate/create_abraham_histories.rb"
|
||||
migration_template "migration.rb", "db/migrate/create_walter_histories.rb"
|
||||
end
|
||||
|
||||
def create_initializer
|
||||
return if options["skip-initializer"]
|
||||
|
||||
copy_file "initializer.rb", "config/initializers/abraham.rb"
|
||||
copy_file "abraham.yml", "config/abraham.yml"
|
||||
copy_file "initializer.rb", "config/initializers/walter.rb"
|
||||
end
|
||||
|
||||
def create_config
|
||||
return if options["skip-config"]
|
||||
|
||||
copy_file "walter.yml", "config/walter.yml"
|
||||
end
|
||||
end
|
||||
end
|
10
lib/generators/walter/templates/initializer.rb
Normal file
10
lib/generators/walter/templates/initializer.rb
Normal file
@ -0,0 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
Rails.application.configure do
|
||||
tours_path ="app/tours"
|
||||
walter_config = Rails.application.config_for :walter
|
||||
config.walter = ActiveSupport::OrderedOptions.new
|
||||
config.walter.tour_options = walter_config[:tour_options]
|
||||
config.walter.tours_path = tours_path
|
||||
Walter::Tourguide.load_tours(tours_path)
|
||||
end
|
@ -1,12 +1,12 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CreateAbrahamHistories < ActiveRecord::Migration[5.0]
|
||||
class CreateWalterHistories < ActiveRecord::Migration[5.0]
|
||||
def change
|
||||
create_table :abraham_histories do |t|
|
||||
create_table :walter_histories do |t|
|
||||
t.string :controller_name
|
||||
t.string :action_name
|
||||
t.string :tour_name
|
||||
t.references :creator, null: false, index: true
|
||||
t.string :creator_id, null: false, index: true
|
||||
|
||||
t.timestamps index: true
|
||||
end
|
@ -1,5 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
# desc "Explaining what the task does"
|
||||
# task :abraham do
|
||||
# task :walter do
|
||||
# # Task goes here
|
||||
# end
|
||||
|
15
lib/walter.rb
Normal file
15
lib/walter.rb
Normal file
@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "walter/engine"
|
||||
|
||||
module Walter
|
||||
require 'walter/tourguide'
|
||||
|
||||
def self.load_tours(tp=nil)
|
||||
Walter::Tourguide.instance.load_tours(tp)
|
||||
end
|
||||
|
||||
def self.tours
|
||||
Walter::Tourguide.instance.tours
|
||||
end
|
||||
end
|
@ -2,7 +2,7 @@
|
||||
|
||||
require "rubygems"
|
||||
|
||||
module Abraham
|
||||
module Walter
|
||||
class Engine < ::Rails::Engine
|
||||
end
|
||||
end
|
39
lib/walter/tourguide.rb
Normal file
39
lib/walter/tourguide.rb
Normal file
@ -0,0 +1,39 @@
|
||||
module Walter
|
||||
class Tourguide
|
||||
include Singleton
|
||||
@tours = {}
|
||||
attr_accessor :reload
|
||||
|
||||
def initialize
|
||||
super
|
||||
@reload = true
|
||||
end
|
||||
|
||||
def tours
|
||||
load_tours
|
||||
@tours
|
||||
end
|
||||
|
||||
def load_tours(tours_path=nil)
|
||||
return unless @reload
|
||||
|
||||
@tours = {}
|
||||
tours_path ||= Rails.application.config.walter.tours_path
|
||||
tours_root = Pathname.new(Rails.root.join(tours_path))
|
||||
if Rails.root.join(tours_path).exist?
|
||||
Dir.glob(Rails.root.join("#{tours_path}/**/*.yml")).each do |yml|
|
||||
relative_filename = Pathname.new(yml).relative_path_from(tours_root)
|
||||
# `controller_path` is either "controller_name" or "module_name/controller_name"
|
||||
controller_path, filename = relative_filename.split
|
||||
file_parts = filename.to_s.split(".")
|
||||
action = file_parts[0]
|
||||
locale = file_parts[1]
|
||||
t = YAML.load_file(yml)
|
||||
@tours["#{controller_path}.#{action}.#{locale}"] = t
|
||||
end
|
||||
end
|
||||
puts "#{@tours.size} tours loaded"
|
||||
@reload = ENV['WALTER_RELOAD_TOURS'].present? || Rails.env.development?
|
||||
end
|
||||
end
|
||||
end
|
5
lib/walter/version.rb
Normal file
5
lib/walter/version.rb
Normal file
@ -0,0 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Walter
|
||||
VERSION = "2.5"
|
||||
end
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "abraham",
|
||||
"name": "walter",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"js-cookie": "^2.2.0",
|
||||
"shepherd.js": "^6.0.0-beta"
|
||||
"shepherd.js": "^8.3.1"
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
require "test_helper"
|
||||
|
||||
class Abraham::Test < ActiveSupport::TestCase
|
||||
class Walter::Test < ActiveSupport::TestCase
|
||||
test "truth" do
|
||||
assert_kind_of Module, Abraham
|
||||
assert_kind_of Module, Walter
|
||||
end
|
||||
end
|
||||
|
@ -11,5 +11,5 @@
|
||||
// about supported directives.
|
||||
//
|
||||
//= require turbolinks
|
||||
//= require abraham
|
||||
//= require walter
|
||||
//= require_tree .
|
||||
|
@ -10,6 +10,6 @@
|
||||
* files in this directory. Styles in this file should be added after the last require_* statement.
|
||||
* It is generally better to create a new file per style scope.
|
||||
*
|
||||
*= require abraham/theme-default
|
||||
*= require walter/theme-default
|
||||
*= require_tree .
|
||||
*/
|
@ -0,0 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Foobar::DashboardController < ApplicationController
|
||||
def home; end
|
||||
end
|
@ -13,14 +13,14 @@
|
||||
|
||||
<script>
|
||||
document.querySelector("#restart_automatic").addEventListener("click", function() {
|
||||
Abraham.startTour("intro");
|
||||
Walter.startTour("intro");
|
||||
});
|
||||
|
||||
document.querySelector("#show_manual").addEventListener("click", function() {
|
||||
Abraham.startTour("a_manual_tour");
|
||||
Walter.startTour("a_manual_tour");
|
||||
});
|
||||
|
||||
document.querySelector("#show_another_manual").addEventListener("click", function() {
|
||||
Abraham.startTour("another_manual_tour");
|
||||
Walter.startTour("another_manual_tour");
|
||||
});
|
||||
</script>
|
4
test/dummy/app/views/foobar/dashboard/home.html.erb
Normal file
4
test/dummy/app/views/foobar/dashboard/home.html.erb
Normal file
@ -0,0 +1,4 @@
|
||||
<h1>Foobar::Dashboard#home</h1>
|
||||
<p>Find me in app/views/foobar/dashboard/home.html.erb</p>
|
||||
|
||||
We should get a unique tour for this module, not the same one as Dashboard#home
|
@ -15,6 +15,6 @@
|
||||
|
||||
<p><em>current_user.id = <%= current_user.id %></em></p>
|
||||
|
||||
<%= abraham_tour %>
|
||||
<%= walter_tour %>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -5,7 +5,7 @@ require_relative "boot"
|
||||
require "rails/all"
|
||||
|
||||
Bundler.require(*Rails.groups)
|
||||
require "abraham"
|
||||
require "walter"
|
||||
|
||||
module Dummy
|
||||
class Application < Rails::Application
|
||||
|
@ -2,23 +2,23 @@
|
||||
|
||||
Rails.application.configure do
|
||||
tours = {}
|
||||
tours_root = Pathname.new(Rails.root.join("config/tours"))
|
||||
|
||||
if Rails.root.join("config/tours").exist?
|
||||
Dir[Rails.root.join("config/tours/*/")].each do |dir|
|
||||
Dir[dir + "*.yml"].each do |yml|
|
||||
path_parts = yml.split(File::SEPARATOR)
|
||||
controller = path_parts[path_parts.size - 2]
|
||||
file_parts = path_parts[path_parts.size - 1].split(".")
|
||||
action = file_parts[0]
|
||||
locale = file_parts[1]
|
||||
t = YAML.load_file(yml)
|
||||
tours["#{controller}.#{action}.#{locale}"] = t
|
||||
end
|
||||
Dir.glob(Rails.root.join("config/tours/**/*.yml")).each do |yml|
|
||||
relative_filename = Pathname.new(yml).relative_path_from(tours_root)
|
||||
# `controller_path` is either "controller_name" or "module_name/controller_name"
|
||||
controller_path, filename = relative_filename.split
|
||||
file_parts = filename.to_s.split(".")
|
||||
action = file_parts[0]
|
||||
locale = file_parts[1]
|
||||
t = YAML.load_file(yml)
|
||||
tours["#{controller_path}.#{action}.#{locale}"] = t
|
||||
end
|
||||
end
|
||||
|
||||
abraham_config = Rails.application.config_for :abraham
|
||||
config.abraham = ActiveSupport::OrderedOptions.new
|
||||
config.abraham.tour_options = abraham_config[:tour_options]
|
||||
config.abraham.tours = tours
|
||||
walter_config = Rails.application.config_for :walter
|
||||
config.walter = ActiveSupport::OrderedOptions.new
|
||||
config.walter.tour_options = walter_config[:tour_options]
|
||||
config.walter.tours = tours
|
||||
end
|
||||
|
@ -6,5 +6,9 @@ Rails.application.routes.draw do
|
||||
get "dashboard/placement"
|
||||
get "dashboard/missing"
|
||||
|
||||
namespace :foobar do
|
||||
get "dashboard/home"
|
||||
end
|
||||
|
||||
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
|
||||
end
|
||||
|
4
test/dummy/config/tours/foobar/dashboard/home.en.yml
Normal file
4
test/dummy/config/tours/foobar/dashboard/home.en.yml
Normal file
@ -0,0 +1,4 @@
|
||||
module:
|
||||
steps:
|
||||
1:
|
||||
text: "This tour should appear for the Foobar::DashboardController only"
|
@ -1,8 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CreateAbrahamHistories < ActiveRecord::Migration[5.0]
|
||||
class CreateWalterHistories < ActiveRecord::Migration[5.0]
|
||||
def change
|
||||
create_table :abraham_histories do |t|
|
||||
create_table :walter_histories do |t|
|
||||
t.string :controller_name
|
||||
t.string :action_name
|
||||
t.string :tour_name
|
||||
|
@ -12,16 +12,16 @@
|
||||
|
||||
ActiveRecord::Schema.define(version: 2016_11_18_143752) do
|
||||
|
||||
create_table "abraham_histories", force: :cascade do |t|
|
||||
create_table "walter_histories", force: :cascade do |t|
|
||||
t.string "controller_name"
|
||||
t.string "action_name"
|
||||
t.string "tour_name"
|
||||
t.integer "creator_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["created_at"], name: "index_abraham_histories_on_created_at"
|
||||
t.index ["creator_id"], name: "index_abraham_histories_on_creator_id"
|
||||
t.index ["updated_at"], name: "index_abraham_histories_on_updated_at"
|
||||
t.index ["created_at"], name: "index_walter_histories_on_created_at"
|
||||
t.index ["creator_id"], name: "index_walter_histories_on_creator_id"
|
||||
t.index ["updated_at"], name: "index_walter_histories_on_updated_at"
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
require "test_helper"
|
||||
|
||||
class AbrahamHistoriesControllerTest < ActionDispatch::IntegrationTest
|
||||
test "should create AbrahamHistory" do
|
||||
assert_difference ["AbrahamHistory.count"] do
|
||||
post abraham_histories_url, as: :json, params: { abraham_history: { action_name: "foo", controller_name: "bar", tour_name: "baz" } }
|
||||
class WalterHistoriesControllerTest < ActionDispatch::IntegrationTest
|
||||
test "should create WalterHistory" do
|
||||
assert_difference ["WalterHistory.count"] do
|
||||
post walter_histories_url, as: :json, params: { walter_history: { action_name: "foo", controller_name: "bar", tour_name: "baz" } }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -13,7 +13,7 @@ class DashboardControllerTest < ActionDispatch::IntegrationTest
|
||||
|
||||
test "uses configured shepherd configuration" do
|
||||
# No options
|
||||
Rails.configuration.abraham.tour_options = nil
|
||||
Rails.configuration.walter.tour_options = nil
|
||||
get dashboard_home_url
|
||||
assert_response :success
|
||||
assert_select "body script" do |element|
|
||||
@ -22,7 +22,7 @@ class DashboardControllerTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
# Custom options
|
||||
Rails.configuration.abraham.tour_options = '{ defaultStepOptions: { classes: "my-custom-class" } }'
|
||||
Rails.configuration.walter.tour_options = '{ defaultStepOptions: { classes: "my-custom-class" } }'
|
||||
get dashboard_home_url
|
||||
assert_select "body script" do |element|
|
||||
# Config-specified options passed into Tour()
|
||||
|
@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
class Foobar::DashboardControllerTest < ActionDispatch::IntegrationTest
|
||||
test "home should have home tour code" do
|
||||
get foobar_dashboard_home_url
|
||||
assert_response :success
|
||||
|
||||
assert_select "body script" do |element|
|
||||
# it's the Foobar module home tour
|
||||
assert element.text.include? "This tour should appear for the Foobar::DashboardController only"
|
||||
end
|
||||
end
|
||||
end
|
@ -3,7 +3,7 @@ require "application_system_test_case"
|
||||
class ToursTest < ApplicationSystemTestCase
|
||||
setup do
|
||||
@user_id = Random.rand(1..99999)
|
||||
@cookie_name = "abraham-dummy-#{@user_id}-dashboard-home-intro"
|
||||
@cookie_name = "walter-dummy-#{@user_id}-dashboard-home-intro"
|
||||
ApplicationController.any_instance.stubs(:current_user).returns(OpenStruct.new(id: @user_id))
|
||||
end
|
||||
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
require "test_helper"
|
||||
require "rails/generators"
|
||||
require "generators/abraham/install_generator"
|
||||
require "generators/walter/install_generator"
|
||||
|
||||
class InstallGeneratorTest < Rails::Generators::TestCase
|
||||
tests Abraham::Generators::InstallGenerator
|
||||
tests Walter::Generators::InstallGenerator
|
||||
destination File.expand_path("../tmp", __dir__)
|
||||
|
||||
setup :prepare_destination
|
||||
@ -13,7 +13,7 @@ class InstallGeneratorTest < Rails::Generators::TestCase
|
||||
test "should generate a migration" do
|
||||
begin
|
||||
run_generator
|
||||
assert_migration "db/migrate/create_abraham_histories"
|
||||
assert_migration "db/migrate/create_walter_histories"
|
||||
ensure
|
||||
FileUtils.rm_rf destination_root
|
||||
end
|
||||
@ -22,7 +22,7 @@ class InstallGeneratorTest < Rails::Generators::TestCase
|
||||
test "should skip the migration when told to do so" do
|
||||
begin
|
||||
run_generator ["--skip-migration"]
|
||||
assert_no_migration "db/migrate/create_abraham_histories"
|
||||
assert_no_migration "db/migrate/create_walter_histories"
|
||||
ensure
|
||||
FileUtils.rm_rf destination_root
|
||||
end
|
||||
@ -31,8 +31,8 @@ class InstallGeneratorTest < Rails::Generators::TestCase
|
||||
test "should generate an initializer" do
|
||||
begin
|
||||
run_generator
|
||||
assert_file "config/initializers/abraham.rb"
|
||||
assert_file "config/abraham.yml"
|
||||
assert_file "config/initializers/walter.rb"
|
||||
assert_file "config/walter.yml"
|
||||
ensure
|
||||
FileUtils.rm_rf destination_root
|
||||
end
|
||||
@ -41,7 +41,7 @@ class InstallGeneratorTest < Rails::Generators::TestCase
|
||||
test "should skip the initializer when told to do so" do
|
||||
begin
|
||||
run_generator ["--skip-initializer"]
|
||||
assert_no_file "config/initializers/abraham.rb"
|
||||
assert_no_file "config/initializers/walter.rb"
|
||||
ensure
|
||||
FileUtils.rm_rf destination_root
|
||||
end
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
require "test_helper"
|
||||
|
||||
class AbrahamHistoryTest < ActiveSupport::TestCase
|
||||
class WalterHistoryTest < ActiveSupport::TestCase
|
||||
# test "the truth" do
|
||||
# assert true
|
||||
# end
|
||||
|
@ -3,17 +3,16 @@
|
||||
$LOAD_PATH.push File.expand_path("lib", __dir__)
|
||||
|
||||
# Maintain your gem's version:
|
||||
require "abraham/version"
|
||||
require "walter/version"
|
||||
|
||||
# Describe your gem and declare its dependencies:
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "abraham"
|
||||
s.version = Abraham::VERSION
|
||||
s.authors = ["Jonathan Abbett"]
|
||||
s.email = ["jonathan@act.md"]
|
||||
s.homepage = "https://github.com/actmd/abraham"
|
||||
s.summary = "Trackable application tours for Rails with i18n support, based on Shepherd.js."
|
||||
s.description = "Trackable application tours for Rails with i18n support, based on Shepherd.js."
|
||||
s.name = "walter"
|
||||
s.version = Walter::VERSION
|
||||
s.authors = ["Mike Sutton"]
|
||||
s.email = ["tech@wizewerx.com"]
|
||||
s.summary = "Application tours for Rails"
|
||||
s.description = "Application tours for Rails"
|
||||
s.license = "MIT"
|
||||
|
||||
s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"]
|
Loading…
x
Reference in New Issue
Block a user