pakyow 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/LICENSE +1 -1
- data/README.md +4 -1
- data/bin/pakyow +2 -16
- data/lib/generators/pakyow/app/app_generator.rb +46 -13
- data/lib/generators/pakyow/app/templates/Gemfile +8 -7
- data/lib/generators/pakyow/app/templates/README.md +2 -2
- data/lib/generators/pakyow/app/templates/app/setup.rb +10 -19
- data/lib/generators/pakyow/app/templates/app/views/_templates/default.html +3 -1
- data/lib/generators/pakyow/app/templates/env +1 -0
- data/lib/generators/pakyow/app/templates/env.example +3 -0
- data/lib/generators/pakyow/app/templates/gitignore +8 -0
- data/lib/generators/pakyow/app/templates/public/scripts/ring/components/fastlink.js +3 -2
- data/lib/generators/pakyow/app/templates/public/scripts/ring/components/fastlink.min.js +1 -1
- data/lib/generators/pakyow/app/templates/public/scripts/ring/components/ga.js +34 -0
- data/lib/generators/pakyow/app/templates/public/scripts/ring/components/ga.min.js +1 -0
- data/lib/generators/pakyow/app/templates/public/scripts/ring/components/modal.js +1 -1
- data/lib/generators/pakyow/app/templates/public/scripts/ring/components/modal.min.js +1 -1
- data/lib/generators/pakyow/app/templates/public/scripts/ring/components/mutable.js +5 -1
- data/lib/generators/pakyow/app/templates/public/scripts/ring/components/mutable.min.js +1 -1
- data/lib/generators/pakyow/app/templates/public/scripts/ring/components/navigator.js +10 -6
- data/lib/generators/pakyow/app/templates/public/scripts/ring/components/navigator.min.js +1 -1
- data/lib/generators/pakyow/app/templates/public/scripts/ring/pakyow.js +175 -45
- data/lib/generators/pakyow/app/templates/public/scripts/ring/pakyow.min.js +1 -1
- data/lib/generators/pakyow/app/templates/rspec +3 -0
- data/lib/pakyow.rb +1 -1
- data/lib/pakyow/command_line_interface.rb +79 -0
- data/lib/pakyow/commands/console.rb +27 -0
- data/lib/pakyow/commands/console_methods.rb +10 -0
- data/lib/pakyow/commands/server.rb +38 -0
- data/lib/pakyow/version.rb +3 -0
- metadata +58 -27
- data/lib/commands/USAGE +0 -9
- data/lib/commands/USAGE-CONSOLE +0 -12
- data/lib/commands/USAGE-NEW +0 -11
- data/lib/commands/USAGE-SERVER +0 -16
- data/lib/commands/console.rb +0 -17
- data/lib/commands/server.rb +0 -27
- data/lib/version.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 199c2331bc67c6b913a5408523fc60019770d551
|
4
|
+
data.tar.gz: b6e2c05f9d55ca795ffb44cf9ed0f7a21c22837a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f0bfd078e041e64094ecbba209afdf4b761d760afcabe795b0b83363f112edc20ac1af5167ce63ad5bae5ab429f0dc683747d7db843a6e09fc7c4b0b60e2c46
|
7
|
+
data.tar.gz: 8191df207e1ec7e2211dbe8252c714c7b62b7a078b6cefa88c85ed493686030b1720c9d47b9f30f220faa98443afbe8fb2b88638c987f1796b0502a1b3266926
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
# 0.11.0
|
2
|
+
|
3
|
+
* Generated app updates:
|
4
|
+
* Uses dotenv for config management
|
5
|
+
* Breaks middleware into pluggable pieces
|
6
|
+
* Dynamically sets app name in config
|
7
|
+
* Creates a random session secret
|
8
|
+
* Updates Ring to 0.2.4
|
9
|
+
* Evaluates app template as erb
|
10
|
+
* Improves CLI, including new `version` command
|
11
|
+
* Moves everything into the Pakyow namespace
|
12
|
+
* Adds ASCII art to `server` command \o/
|
13
|
+
|
1
14
|
# 0.10.2 / 2015-11-15
|
2
15
|
|
3
16
|
* Updates Ring to latest in generator
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
[gem]: https://rubygems.org/gems/pakyow
|
2
2
|
[travis]: https://travis-ci.org/pakyow/pakyow
|
3
3
|
[gemnasium]: https://gemnasium.com/pakyow/pakyow
|
4
|
+
[inchpages]: http://inch-ci.org/github/pakyow/pakyow
|
5
|
+
[codeclimate]: https://codeclimate.com/github/pakyow/pakyow
|
4
6
|
|
5
7
|
# Pakyow Framework [](https://gitter.im/pakyow/chat)
|
6
8
|
|
@@ -46,6 +48,7 @@ implements this protocol on the backend for initial rendering and in
|
|
46
48
|
[][gem]
|
47
49
|
[][travis]
|
48
50
|
[][gemnasium]
|
51
|
+
[][inchpages]
|
49
52
|
|
50
53
|
---
|
51
54
|
|
@@ -61,7 +64,7 @@ implements this protocol on the backend for initial rendering and in
|
|
61
64
|
|
62
65
|
3. Move to the new directory and start the server:
|
63
66
|
|
64
|
-
`cd webapp; pakyow server`
|
67
|
+
`cd webapp; bundle exec pakyow server`
|
65
68
|
|
66
69
|
4. You'll find your project running at [http://localhost:3000](http://localhost:3000)!
|
67
70
|
|
data/bin/pakyow
CHANGED
@@ -1,18 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
case ARGV.first
|
6
|
-
when 'new'
|
7
|
-
ARGV.shift
|
8
|
-
require File.join(PAK_PATH, 'generators/pakyow/app/app_generator')
|
9
|
-
Pakyow::Generators::AppGenerator.start
|
10
|
-
when 'server', 's'
|
11
|
-
ARGV.shift
|
12
|
-
require File.join(PAK_PATH, 'commands/server')
|
13
|
-
when 'console', 'c'
|
14
|
-
ARGV.shift
|
15
|
-
require File.join(PAK_PATH, 'commands/console')
|
16
|
-
when '--help', '-h', nil
|
17
|
-
puts File.open(File.join(PAK_PATH, 'commands/USAGE')).read
|
18
|
-
end
|
3
|
+
require "pakyow/command_line_interface"
|
4
|
+
Pakyow::CommandLineInterface.start
|
@@ -1,20 +1,25 @@
|
|
1
|
+
require 'erb'
|
1
2
|
require 'fileutils'
|
3
|
+
require 'securerandom'
|
4
|
+
require 'pakyow/version.rb'
|
2
5
|
|
3
6
|
module Pakyow
|
4
7
|
module Generators
|
5
8
|
class AppGenerator
|
6
9
|
class << self
|
7
|
-
def start
|
8
|
-
|
9
|
-
|
10
|
-
puts File.open(File.join(PAK_PATH, 'commands/USAGE-NEW')).read
|
11
|
-
else
|
12
|
-
generator = self.new(ARGV.first)
|
13
|
-
generator.build
|
14
|
-
end
|
10
|
+
def start(destination)
|
11
|
+
generator = self.new(destination)
|
12
|
+
generator.build
|
15
13
|
end
|
16
14
|
end
|
17
15
|
|
16
|
+
FILENAME_TRANSLATIONS = {
|
17
|
+
'rspec' => '.rspec',
|
18
|
+
'gitignore' => '.gitignore',
|
19
|
+
'env' => '.env',
|
20
|
+
'env.example' => '.env.example'
|
21
|
+
}
|
22
|
+
|
18
23
|
def initialize(dest)
|
19
24
|
@src = "#{File.expand_path('../', __FILE__)}/templates/."
|
20
25
|
@dest = dest
|
@@ -38,23 +43,51 @@ module Pakyow
|
|
38
43
|
end
|
39
44
|
|
40
45
|
exec
|
41
|
-
puts "Done! Run `cd #{@dest}; pakyow server` to get started!"
|
46
|
+
puts "Done! Run `cd #{@dest}; bundle exec pakyow server` to get started!"
|
42
47
|
end
|
43
48
|
|
44
49
|
protected
|
45
50
|
|
46
|
-
# copies src files to dest
|
47
51
|
def copy
|
48
|
-
FileUtils.
|
52
|
+
FileUtils.mkdir(@dest) unless File.exists?(@dest)
|
53
|
+
|
54
|
+
Dir.glob(File.join(@src, '**', '*')).each do |path|
|
55
|
+
relative_path = path[@src.length..-1]
|
56
|
+
generated_path = File.join(@dest, File.dirname(relative_path), translated_filename(File.basename(relative_path)))
|
57
|
+
|
58
|
+
if File.directory?(path)
|
59
|
+
FileUtils.mkdir(generated_path)
|
60
|
+
next
|
61
|
+
end
|
62
|
+
|
63
|
+
erb = ERB.new(File.read(path))
|
64
|
+
File.open(generated_path, 'w') { |f| f.write(erb.result(binding)) }
|
65
|
+
end
|
49
66
|
end
|
50
67
|
|
51
|
-
# performs and other setup (e.g. bundle install)
|
52
68
|
def exec
|
53
69
|
FileUtils.cd(@dest) do
|
54
70
|
puts "Running `bundle install` in #{Dir.pwd}"
|
55
|
-
system("bundle install")
|
71
|
+
system("bundle install --binstubs")
|
56
72
|
end
|
57
73
|
end
|
74
|
+
|
75
|
+
def generating_locally?
|
76
|
+
local_pakyow = Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.group_by{ |g| g.name }.detect{|k,v| k == 'pakyow'}
|
77
|
+
!local_pakyow || local_pakyow.last.last.version < Gem::Version.new(Pakyow::VERSION)
|
78
|
+
end
|
79
|
+
|
80
|
+
def translated_filename(filename)
|
81
|
+
FILENAME_TRANSLATIONS.fetch(filename, filename)
|
82
|
+
end
|
83
|
+
|
84
|
+
def generate_session_secret
|
85
|
+
SecureRandom.hex(64)
|
86
|
+
end
|
87
|
+
|
88
|
+
def app_name
|
89
|
+
File.basename(@dest)
|
90
|
+
end
|
58
91
|
end
|
59
92
|
end
|
60
93
|
end
|
@@ -1,15 +1,16 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
gem 'pakyow', '~> 0.10'
|
8
|
-
|
2
|
+
<% if generating_locally? %>
|
3
|
+
gem 'pakyow', github: 'pakyow/pakyow'
|
4
|
+
<% else %>
|
5
|
+
gem 'pakyow', '~> <%= Pakyow::VERSION %>'
|
6
|
+
<% end %>
|
9
7
|
# app server
|
10
8
|
gem 'puma', platforms: :ruby
|
11
9
|
gem 'thin', platforms: :mswin
|
12
10
|
|
11
|
+
# use dotenv to load environment variables
|
12
|
+
gem 'dotenv'
|
13
|
+
|
13
14
|
group :test do
|
14
15
|
gem 'rspec'
|
15
16
|
end
|
@@ -4,13 +4,13 @@ This is a Pakyow v0.10 project.
|
|
4
4
|
|
5
5
|
Start the server:
|
6
6
|
|
7
|
-
`pakyow server`
|
7
|
+
`bundle exec pakyow server`
|
8
8
|
|
9
9
|
You'll find your app running at [http://localhost:3000](http://localhost:3000)!
|
10
10
|
|
11
11
|
Need to interact with your code? Fire up a console:
|
12
12
|
|
13
|
-
`pakyow console`
|
13
|
+
`bundle exec pakyow console`
|
14
14
|
|
15
15
|
# Next Steps
|
16
16
|
|
@@ -2,32 +2,23 @@ require 'bundler/setup'
|
|
2
2
|
require 'pakyow'
|
3
3
|
|
4
4
|
Pakyow::App.define do
|
5
|
-
configure
|
5
|
+
configure do
|
6
6
|
Bundler.require :default, Pakyow::Config.env
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
# put development config here
|
14
|
-
end
|
8
|
+
if defined?(Dotenv)
|
9
|
+
env_path = ".env.#{Pakyow::Config.env}"
|
10
|
+
Dotenv.load env_path if File.exist?(env_path)
|
11
|
+
Dotenv.load
|
12
|
+
end
|
15
13
|
|
16
|
-
|
17
|
-
# an environment for running the front-end prototype with no backend
|
18
|
-
app.ignore_routes = true
|
14
|
+
app.name = '<%= app_name %>'
|
19
15
|
end
|
20
16
|
|
21
|
-
configure :
|
22
|
-
#
|
17
|
+
configure :development do
|
18
|
+
# development config goes here
|
23
19
|
end
|
24
20
|
|
25
21
|
configure :production do
|
26
|
-
#
|
27
|
-
end
|
28
|
-
|
29
|
-
middleware do |builder|
|
30
|
-
# TODO: you will most definitely want to change this secret
|
31
|
-
builder.use Rack::Session::Cookie, key: "#{Pakyow::Config.app.name}.session", secret: 'sekret'
|
22
|
+
# production config goes here
|
32
23
|
end
|
33
24
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
<html>
|
3
3
|
<head>
|
4
4
|
<title>
|
5
|
-
|
5
|
+
<%= app_name %>
|
6
6
|
</title>
|
7
7
|
|
8
8
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0" name="viewport">
|
@@ -13,6 +13,8 @@
|
|
13
13
|
<link rel="stylesheet" type="text/css" href="/styles/pakyow-css/theme.css">
|
14
14
|
|
15
15
|
<script src="/scripts/ring/pakyow.js"></script>
|
16
|
+
|
17
|
+
<meta charset="UTF-8">
|
16
18
|
</head>
|
17
19
|
|
18
20
|
<body>
|
@@ -0,0 +1 @@
|
|
1
|
+
SESSION_SECRET=<%= generate_session_secret %>
|
@@ -1,8 +1,9 @@
|
|
1
1
|
pw.component.register('fastlink', function (view, config) {
|
2
|
-
var that = this;
|
3
|
-
|
4
2
|
if (window.history) {
|
5
3
|
view.node.addEventListener('click', function (evt) {
|
4
|
+
// don't break open in new tab!
|
5
|
+
if (evt.metaKey || evt.ctrlKey) return;
|
6
|
+
|
6
7
|
evt.preventDefault();
|
7
8
|
window.history.pushState({ uri: this.href }, this.href, this.href);
|
8
9
|
return false;
|
@@ -1 +1 @@
|
|
1
|
-
pw.component.register("fastlink",function(t,e){window.history&&t.node.addEventListener("click",function(t){return t.preventDefault(),window.history.pushState({uri:this.href},this.href,this.href),!1})});
|
1
|
+
pw.component.register("fastlink",function(t,e){window.history&&t.node.addEventListener("click",function(t){return t.metaKey||t.ctrlKey?void 0:(t.preventDefault(),window.history.pushState({uri:this.href},this.href,this.href),!1)})});
|
@@ -0,0 +1,34 @@
|
|
1
|
+
/*
|
2
|
+
Ring.js - Google Analytics Component
|
3
|
+
|
4
|
+
Sets up Google Analytics and tracks the immediate pageview along with any
|
5
|
+
pageviews that occur over a WebSocket connection with Navigator. To use,
|
6
|
+
attach the component to the <body> tag and configure the trackingId:
|
7
|
+
|
8
|
+
<body data-ui="ga" data-config="trackingId: yourTrackingIdHere">
|
9
|
+
|
10
|
+
It will automatically ignore pageviews that occur locally.
|
11
|
+
*/
|
12
|
+
|
13
|
+
pw.component.register('ga', function (view, config) {
|
14
|
+
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
15
|
+
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
16
|
+
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
17
|
+
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
18
|
+
ga('create', config.trackingId, 'auto');
|
19
|
+
|
20
|
+
this.track = function (uri) {
|
21
|
+
if (document.domain.indexOf('local') != -1) {
|
22
|
+
return;
|
23
|
+
}
|
24
|
+
|
25
|
+
ga('send', 'pageview', uri);
|
26
|
+
};
|
27
|
+
|
28
|
+
this.listen('navigator:change', function (payload) {
|
29
|
+
this.track(payload.uri);
|
30
|
+
});
|
31
|
+
|
32
|
+
// track the current pageview
|
33
|
+
this.track(location.pathname);
|
34
|
+
});
|
@@ -0,0 +1 @@
|
|
1
|
+
pw.component.register("ga",function(t,n){!function(t,n,e,a,c,i,o){t.GoogleAnalyticsObject=c,t[c]=t[c]||function(){(t[c].q=t[c].q||[]).push(arguments)},t[c].l=1*new Date,i=n.createElement(e),o=n.getElementsByTagName(e)[0],i.async=1,i.src=a,o.parentNode.insertBefore(i,o)}(window,document,"script","//www.google-analytics.com/analytics.js","ga"),ga("create",n.trackingId,"auto"),this.track=function(t){-1==document.domain.indexOf("local")&&ga("send","pageview",t)},this.listen("navigator:change",function(t){this.track(t.uri)}),this.track(location.pathname)});
|
@@ -1 +1 @@
|
|
1
|
-
pw.component.register("modal",function(t,e,n,o){var a,i,d,l=this,r="modal:"+o;(d=document.querySelector('*[data-template="ui-modal-blinder"]'))&&(d=d.cloneNode(!0)),this.listen(r+":navigator:enter",function(t){a||(d?(a=d.cloneNode(!0),i=a.querySelector('*[data-template="ui-modal-content"]'),document.body.appendChild(a),a.removeAttribute("data-template"),i.removeAttribute("data-template")):(a=document.createElement("DIV"),a.classList.add("ui-modal-blinder"),i=document.createElement("DIV"),i.classList.add("ui-modal"),a.appendChild(i),document.body.appendChild(a)),a.addEventListener("click",function(t){if(t.target===a){t.preventDefault(),l.close();var e=window.location.pathname,n={uri:e};window.history.pushState(n,e,e)}})),i.innerHTML=t.body,pw.component.findAndInit(a),a.classList.add("ui-appear")}),this.listen(r+":navigator:exit",function(){l.close()}),this.listen(r+":navigator:boot",function(t){l.load(t)}),t.node.addEventListener("click",function(t){return t.preventDefault(),l.load(this.href),!1}),this.load=function(t){if(!window.socket)return void(document.location=t);var n={uri:t,context:"modal:"+o};e.container&&(n.container=e.container),e.partial&&(n.partial=e.partial),window.history.pushState(n,t,t)},this.close=function(){a&&i&&(pw.node.remove(a),a=null,i=null)}});
|
1
|
+
pw.component.register("modal",function(t,e,n,o){var a,i,d,l=this,r="modal:"+o;(d=document.querySelector('*[data-template="ui-modal-blinder"]'))&&(d=d.cloneNode(!0)),this.listen(r+":navigator:enter",function(t){a||(d?(a=d.cloneNode(!0),i=a.querySelector('*[data-template="ui-modal-content"]'),document.body.appendChild(a),a.removeAttribute("data-template"),i.removeAttribute("data-template")):(a=document.createElement("DIV"),a.classList.add("ui-modal-blinder"),i=document.createElement("DIV"),i.classList.add("ui-modal"),a.appendChild(i),document.body.appendChild(a)),a.addEventListener("click",function(t){if(t.target===a){t.preventDefault(),l.close();var e=window.location.pathname,n={uri:e};window.history.pushState(n,e,e)}})),i.innerHTML=t.body,pw.component.findAndInit(a),a.classList.add("ui-appear")}),this.listen(r+":navigator:exit",function(){l.close()}),this.listen(r+":navigator:boot",function(t){l.load(t)}),t.node.addEventListener("click",function(t){return t.preventDefault(),l.load(e.href||this.href),!1}),this.load=function(t){if(!window.socket)return void(document.location=t);var n={uri:t,context:"modal:"+o};e.container&&(n.container=e.container),e.partial&&(n.partial=e.partial),window.history.pushState(n,t,t)},this.close=function(){a&&i&&(pw.node.remove(a),a=null,i=null)}});
|
@@ -54,13 +54,17 @@ pw.component.register('mutable', function (view, config) {
|
|
54
54
|
}
|
55
55
|
} else if (res.status === 400) {
|
56
56
|
// bad request
|
57
|
+
pw.component.broadcast('response:received', { response: res });
|
57
58
|
return;
|
58
59
|
} else {
|
59
60
|
self.state.rollback();
|
60
61
|
}
|
61
62
|
|
62
63
|
pw.component.broadcast('response:received', { response: res });
|
63
|
-
|
64
|
+
|
65
|
+
if (config.revert !== 'false') {
|
66
|
+
self.revert();
|
67
|
+
}
|
64
68
|
});
|
65
69
|
}
|
66
70
|
});
|
@@ -1 +1 @@
|
|
1
|
-
pw.component.register("mutable",function(e,t){this.mutation=function(
|
1
|
+
pw.component.register("mutable",function(e,t){this.mutation=function(o){if(!window.socket)return void e.node.submit();var n=pw.util.dup(o);delete n.__nested,delete n.scope,delete n.id;var i={action:"call-route"};if("FORM"===e.node.tagName){if(e.node.querySelector('input[type="file"]'))return void e.node.submit();var r,s=e.node.querySelector('input[name="_method"]');r=s?s.value:e.node.getAttribute("method"),i.method=r,i.uri=e.node.getAttribute("action"),i.input=pw.node.serialize(e.node)}else{var a={};a[o.scope]=n,i.input=a}var d=this;window.socket.send(i,function(e){if(302===e.status){var o=e.headers.Location;o!=window.location.pathname||window.context&&"default"===window.context.name?history.pushState({uri:o},o,o):history.pushState({uri:o},o,o)}else{if(400===e.status)return void pw.component.broadcast("response:received",{response:e});d.state.rollback()}pw.component.broadcast("response:received",{response:e}),"false"!==t.revert&&d.revert()})}});
|
@@ -80,6 +80,9 @@ function handleState(state, direction) {
|
|
80
80
|
return;
|
81
81
|
}
|
82
82
|
|
83
|
+
uri = uri.replace(document.location.origin, '');
|
84
|
+
pw.component.broadcast('navigator:change', { uri: uri });
|
85
|
+
|
83
86
|
if (state.context) {
|
84
87
|
state.r_uri = document.location.pathname + '#:' + state.context + '/' + uri;
|
85
88
|
|
@@ -135,16 +138,17 @@ function handleState(state, direction) {
|
|
135
138
|
var body = payload.body[0];
|
136
139
|
|
137
140
|
if (body.match(/<title>/)) {
|
138
|
-
|
141
|
+
var title = body.split(/<title>/)[1].split('</title>')[0];
|
142
|
+
document.querySelector('title').innerHTML = title;
|
139
143
|
}
|
140
144
|
|
141
|
-
|
142
|
-
|
143
|
-
} else {
|
144
|
-
document.body.innerHTML = body;
|
145
|
-
}
|
145
|
+
var doc = document.documentElement.cloneNode();
|
146
|
+
doc.innerHTML = body;
|
146
147
|
|
148
|
+
document.body.innerHTML = doc.querySelector('body').innerHTML;
|
147
149
|
pw.component.findAndInit(document.querySelectorAll('body')[0]);
|
150
|
+
|
151
|
+
document.body.scrollTop = document.documentElement.scrollTop = 0;
|
148
152
|
}
|
149
153
|
});
|
150
154
|
}
|
@@ -1 +1 @@
|
|
1
|
-
function boot(){if(!window.socket)return void setTimeout(boot,100);if(window.location.hash){var t=window.location.hash.split("#:")[1].split("/"),n=t.shift(),o=t.join("/");pw.component.broadcast(n+":navigator:boot",o)}}function handleState(t,n){var o=t.uri||t.url;if(!window.socket)return void(document.location=o);if(t.context)t.r_uri=document.location.pathname+"#:"+t.context+"/"+o,window.context={_state:t,name:t.context,uri:t.r_uri,container:t.container,partial:t.partial};else if(t.r_uri=o,"default"!==window.context.name){if("back"===n)return pw.component.broadcast(window.context.name+":navigator:exit"),void(window.context={name:"default",uri:t.uri});t.r_uri=document.location.pathname+"#:"+window.context.name+"/"+o,t.context=window.context.name,t.container=window.context.container,t.partial=window.context.partial}var
|
1
|
+
function boot(){if(!window.socket)return void setTimeout(boot,100);if(window.location.hash){var t=window.location.hash.split("#:")[1].split("/"),n=t.shift(),o=t.join("/");pw.component.broadcast(n+":navigator:boot",o)}}function handleState(t,n){var o=t.uri||t.url;if(!window.socket)return void(document.location=o);if(o=o.replace(document.location.origin,""),pw.component.broadcast("navigator:change",{uri:o}),t.context)t.r_uri=document.location.pathname+"#:"+t.context+"/"+o,window.context={_state:t,name:t.context,uri:t.r_uri,container:t.container,partial:t.partial};else if(t.r_uri=o,"default"!==window.context.name){if("back"===n)return pw.component.broadcast(window.context.name+":navigator:exit"),void(window.context={name:"default",uri:t.uri});t.r_uri=document.location.pathname+"#:"+window.context.name+"/"+o,t.context=window.context.name,t.container=window.context.container,t.partial=window.context.partial}var e={uri:o,action:"call-route",method:"get"};t.container&&(e.container=t.container),t.partial&&(e.partial=t.partial),window.socket.send(e,function(n){if(t.context)pw.component.broadcast(t.context+":navigator:enter",n);else{var o=n.body[0];if(o.match(/<title>/)){var e=o.split(/<title>/)[1].split("</title>")[0];document.querySelector("title").innerHTML=e}var i=document.documentElement.cloneNode();i.innerHTML=o,document.body.innerHTML=i.querySelector("body").innerHTML,pw.component.findAndInit(document.querySelectorAll("body")[0]),document.body.scrollTop=document.documentElement.scrollTop=0}})}!function(t){if(pw.init.register(boot),t){var n=!1,o=t.pushState;t.pushState=function(e,i,a){return n=!0,"function"==typeof t.onpushstate&&t.onpushstate({state:e}),a==window.location.pathname?(pw.component.broadcast(window.context.name+":navigator:exit"),window.context={_state:e,name:"default",uri:window.location.href},e.r_uri=a):handleState(e,"forward"),o.apply(t,[e,i,e.r_uri])},window.onpopstate=function(t){if(n){var o=t.state;o||(o={}),o.uri||(o.uri=window.context.uri),handleState(o,"back")}}}}(window.history),window.context={name:"default",uri:window.location.href};
|
@@ -1,5 +1,5 @@
|
|
1
1
|
var pw = {
|
2
|
-
version: '0.
|
2
|
+
version: '0.2.4'
|
3
3
|
};
|
4
4
|
|
5
5
|
(function() {
|
@@ -142,7 +142,7 @@ pw.node = {
|
|
142
142
|
}
|
143
143
|
|
144
144
|
var next = node.parentNode;
|
145
|
-
if (next !== document) {
|
145
|
+
if (next && next !== document) {
|
146
146
|
return pw.node.inForm(next);
|
147
147
|
}
|
148
148
|
},
|
@@ -154,7 +154,7 @@ pw.node = {
|
|
154
154
|
}
|
155
155
|
|
156
156
|
var next = node.parentNode;
|
157
|
-
if (next !== document) {
|
157
|
+
if (next && next !== document) {
|
158
158
|
return pw.node.component(next);
|
159
159
|
}
|
160
160
|
},
|
@@ -166,7 +166,7 @@ pw.node = {
|
|
166
166
|
}
|
167
167
|
|
168
168
|
var next = node.parentNode;
|
169
|
-
if (next !== document) {
|
169
|
+
if (next && next !== document) {
|
170
170
|
return pw.node.scope(next);
|
171
171
|
}
|
172
172
|
},
|
@@ -178,7 +178,7 @@ pw.node = {
|
|
178
178
|
}
|
179
179
|
|
180
180
|
var next = node.parentNode;
|
181
|
-
if (next !== document) {
|
181
|
+
if (next && next !== document) {
|
182
182
|
return pw.node.scopeName(next);
|
183
183
|
}
|
184
184
|
},
|
@@ -190,7 +190,7 @@ pw.node = {
|
|
190
190
|
}
|
191
191
|
|
192
192
|
var next = node.parentNode;
|
193
|
-
if (next !== document) {
|
193
|
+
if (next && next !== document) {
|
194
194
|
return pw.node.prop(next);
|
195
195
|
}
|
196
196
|
},
|
@@ -202,7 +202,7 @@ pw.node = {
|
|
202
202
|
}
|
203
203
|
|
204
204
|
var next = node.parentNode;
|
205
|
-
if (next !== document) {
|
205
|
+
if (next && next !== document) {
|
206
206
|
return pw.node.propName(next);
|
207
207
|
}
|
208
208
|
},
|
@@ -215,11 +215,11 @@ pw.node = {
|
|
215
215
|
},
|
216
216
|
|
217
217
|
// creates a context in which view manipulations can occur
|
218
|
-
|
218
|
+
invoke: function(node, cb) {
|
219
219
|
cb.call(node);
|
220
220
|
},
|
221
221
|
|
222
|
-
|
222
|
+
invokeWithData: function(node, data, cb) {
|
223
223
|
if (pw.node.isNodeList(node)) {
|
224
224
|
node = pw.node.toA(node);
|
225
225
|
}
|
@@ -257,14 +257,14 @@ pw.node = {
|
|
257
257
|
},
|
258
258
|
|
259
259
|
repeat: function(node, data, cb) {
|
260
|
-
pw.node.
|
260
|
+
pw.node.invokeWithData(pw.node.match(node, data), data, cb);
|
261
261
|
},
|
262
262
|
|
263
263
|
// binds an object to a node
|
264
264
|
bind: function (data, node, cb) {
|
265
265
|
var scope = pw.node.findBindings(node)[0];
|
266
266
|
|
267
|
-
pw.node.
|
267
|
+
pw.node.invokeWithData(node, data, function(dm) {
|
268
268
|
if (!dm) {
|
269
269
|
return;
|
270
270
|
}
|
@@ -389,7 +389,9 @@ pw.node = {
|
|
389
389
|
} else if (node.tagName === 'TEXTAREA' || pw.node.isSelfClosingTag(node)) {
|
390
390
|
node.value = value;
|
391
391
|
} else {
|
392
|
-
|
392
|
+
if (value) {
|
393
|
+
node.innerHTML = value;
|
394
|
+
}
|
393
395
|
}
|
394
396
|
},
|
395
397
|
|
@@ -725,6 +727,12 @@ pw_State.prototype = {
|
|
725
727
|
|
726
728
|
// gets the current represented state from the node and diffs it with the current state
|
727
729
|
diffNode: function (node) {
|
730
|
+
if (node.hasAttribute('data-ui')) {
|
731
|
+
return {
|
732
|
+
'__nested': pw.state.build(pw.node.significant(node))
|
733
|
+
};
|
734
|
+
}
|
735
|
+
|
728
736
|
return pw.state.build(pw.node.significant(pw.node.scope(node)))[0];
|
729
737
|
},
|
730
738
|
|
@@ -758,7 +766,7 @@ pw_State.prototype = {
|
|
758
766
|
this.snapshots.push(copy);
|
759
767
|
},
|
760
768
|
|
761
|
-
|
769
|
+
remove: function (state) {
|
762
770
|
var copy = this.copy();
|
763
771
|
var match = copy.find(function (s) {
|
764
772
|
return s.id === state.id;
|
@@ -793,8 +801,15 @@ pw.view = {
|
|
793
801
|
},
|
794
802
|
|
795
803
|
fromStr: function (str) {
|
796
|
-
var
|
804
|
+
var nodeType = 'div';
|
805
|
+
|
806
|
+
if (str.match(/^<tr/) || str.match(/^<tbody/)) {
|
807
|
+
nodeType = 'table';
|
808
|
+
}
|
809
|
+
|
810
|
+
var e = document.createElement(nodeType);
|
797
811
|
e.innerHTML = str;
|
812
|
+
|
798
813
|
return pw.view.init(e.childNodes[0]);
|
799
814
|
}
|
800
815
|
};
|
@@ -839,16 +854,16 @@ pw_View.prototype = {
|
|
839
854
|
return pw.attrs.init(this);
|
840
855
|
},
|
841
856
|
|
842
|
-
|
843
|
-
pw.node.
|
857
|
+
invoke: function (cb) {
|
858
|
+
pw.node.invoke(this.node, cb);
|
844
859
|
},
|
845
860
|
|
846
861
|
match: function (data) {
|
847
862
|
pw.node.match(this.node, data);
|
848
863
|
},
|
849
864
|
|
850
|
-
|
851
|
-
pw.node.
|
865
|
+
invokeWithData: function (data, cb) {
|
866
|
+
pw.node.invokeWithData(this.node, data, cb);
|
852
867
|
},
|
853
868
|
|
854
869
|
repeat: function (data, cb) {
|
@@ -861,6 +876,41 @@ pw_View.prototype = {
|
|
861
876
|
|
862
877
|
apply: function (data, cb) {
|
863
878
|
pw.node.apply(data, this.node, cb);
|
879
|
+
},
|
880
|
+
|
881
|
+
use: function (version, cb) {
|
882
|
+
var self = this;
|
883
|
+
|
884
|
+
if (this.node.getAttribute('data-version') != version) {
|
885
|
+
this.node.setAttribute('data-version', version);
|
886
|
+
|
887
|
+
var lookup = {
|
888
|
+
scope: this.node.getAttribute('data-scope'),
|
889
|
+
version: version
|
890
|
+
};
|
891
|
+
|
892
|
+
window.socket.fetchView(lookup, function (view) {
|
893
|
+
view.node.setAttribute('data-channel', self.node.getAttribute('data-channel'));
|
894
|
+
pw.node.replace(self.node, view.node);
|
895
|
+
self.node = view.node;
|
896
|
+
cb();
|
897
|
+
});
|
898
|
+
} else {
|
899
|
+
cb();
|
900
|
+
}
|
901
|
+
},
|
902
|
+
|
903
|
+
setEndpoint: function (endpoint) {
|
904
|
+
this.endpoint = endpoint;
|
905
|
+
return this;
|
906
|
+
},
|
907
|
+
|
908
|
+
first: function () {
|
909
|
+
return this;
|
910
|
+
},
|
911
|
+
|
912
|
+
length: function () {
|
913
|
+
return 1;
|
864
914
|
}
|
865
915
|
};
|
866
916
|
|
@@ -875,7 +925,7 @@ pw_View.prototype = {
|
|
875
925
|
});
|
876
926
|
|
877
927
|
// pass through functions without view
|
878
|
-
['remove', 'clear', '
|
928
|
+
['remove', 'clear', 'versionName'].forEach(function (method) {
|
879
929
|
pw_View.prototype[method] = function () {
|
880
930
|
return pw.node[method](this.node);
|
881
931
|
};
|
@@ -908,7 +958,7 @@ pw.collection = {
|
|
908
958
|
var pw_Collection = function (views, parent, scope) {
|
909
959
|
this.views = views;
|
910
960
|
this.parent = parent;
|
911
|
-
this.
|
961
|
+
this._scope = scope;
|
912
962
|
};
|
913
963
|
|
914
964
|
pw_Collection.prototype = {
|
@@ -1007,11 +1057,11 @@ pw_Collection.prototype = {
|
|
1007
1057
|
return pw.collection.init(prependedViews);
|
1008
1058
|
},
|
1009
1059
|
|
1010
|
-
|
1011
|
-
pw.node.
|
1060
|
+
invoke: function (cb) {
|
1061
|
+
pw.node.invoke(this.views, cb);
|
1012
1062
|
},
|
1013
1063
|
|
1014
|
-
|
1064
|
+
invokeWithData: function(data, fn) {
|
1015
1065
|
data = Array.ensure(data);
|
1016
1066
|
|
1017
1067
|
this.views.forEach(function (view, i) {
|
@@ -1037,12 +1087,13 @@ pw_Collection.prototype = {
|
|
1037
1087
|
this.views.slice(0).forEach(function (view) {
|
1038
1088
|
var id = view.node.getAttribute('data-id');
|
1039
1089
|
|
1040
|
-
if (!id) {
|
1041
|
-
return;
|
1042
|
-
}
|
1043
|
-
|
1044
|
-
if (!data.find(function (datum) { return datum.id.toString() === id })) {
|
1090
|
+
if (!id && data[0].id) {
|
1045
1091
|
this.removeView(view);
|
1092
|
+
return;
|
1093
|
+
} else if (id) {
|
1094
|
+
if (!data.find(function (datum) { return datum.id && datum.id.toString() === id })) {
|
1095
|
+
this.removeView(view);
|
1096
|
+
}
|
1046
1097
|
}
|
1047
1098
|
}, this);
|
1048
1099
|
|
@@ -1083,12 +1134,12 @@ pw_Collection.prototype = {
|
|
1083
1134
|
|
1084
1135
|
repeat: function (data, fn) {
|
1085
1136
|
this.match(data, function () {
|
1086
|
-
this.
|
1137
|
+
this.invokeWithData(data, fn);
|
1087
1138
|
});
|
1088
1139
|
},
|
1089
1140
|
|
1090
1141
|
bind: function (data, fn) {
|
1091
|
-
this.
|
1142
|
+
this.invokeWithData(data, function(datum) {
|
1092
1143
|
this.bind(datum);
|
1093
1144
|
|
1094
1145
|
if(!(typeof fn === 'undefined')) {
|
@@ -1113,7 +1164,14 @@ pw_Collection.prototype = {
|
|
1113
1164
|
});
|
1114
1165
|
},
|
1115
1166
|
|
1116
|
-
|
1167
|
+
version: function (data, fn) {
|
1168
|
+
var self = this;
|
1169
|
+
this.match(data, function () {
|
1170
|
+
this.invokeWithData(data, fn);
|
1171
|
+
});
|
1172
|
+
},
|
1173
|
+
|
1174
|
+
setEndpoint: function (endpoint) {
|
1117
1175
|
this.endpoint = endpoint;
|
1118
1176
|
return this;
|
1119
1177
|
}
|
@@ -1320,11 +1378,10 @@ pw_Component.prototype = {
|
|
1320
1378
|
|
1321
1379
|
// make it mutable
|
1322
1380
|
var mutableCb = function (evt) {
|
1323
|
-
evt.preventDefault();
|
1324
|
-
|
1325
1381
|
var scope = pw.node.scope(evt.target);
|
1326
1382
|
|
1327
1383
|
if (scope) {
|
1384
|
+
evt.preventDefault();
|
1328
1385
|
self.mutated(scope);
|
1329
1386
|
}
|
1330
1387
|
};
|
@@ -1351,6 +1408,33 @@ pw_Component.prototype = {
|
|
1351
1408
|
pw.component.deregisterForBroadcast(channel, this);
|
1352
1409
|
},
|
1353
1410
|
|
1411
|
+
// Bubbles an event up to a parent component. Intended to be used
|
1412
|
+
// as an alternative to `broadcast` in cases where child components
|
1413
|
+
// have an impact on their parents.
|
1414
|
+
bubble: function (channel, payload) {
|
1415
|
+
var parentComponent = pw.node.component(this.node.parentNode);
|
1416
|
+
|
1417
|
+
(channelBroadcasts[channel] || []).forEach(function (cbTuple) {
|
1418
|
+
if (cbTuple[1].node == parentComponent) {
|
1419
|
+
cbTuple[0].call(cbTuple[1], payload);
|
1420
|
+
}
|
1421
|
+
});
|
1422
|
+
},
|
1423
|
+
|
1424
|
+
// Trickles an event down to child components. Intended to be used
|
1425
|
+
// as an alternative to `broadcast` in cases where parent components
|
1426
|
+
// have an impact on their children.
|
1427
|
+
trickle: function (channel, payload) {
|
1428
|
+
var channels = (channelBroadcasts[channel] || []);
|
1429
|
+
pw.node.toA(this.node.getElementsByTagName('*')).forEach(function (node) {
|
1430
|
+
channels.forEach(function (cbTuple) {
|
1431
|
+
if (cbTuple[1].node == node) {
|
1432
|
+
cbTuple[0].call(cbTuple[1], payload);
|
1433
|
+
}
|
1434
|
+
});
|
1435
|
+
})
|
1436
|
+
},
|
1437
|
+
|
1354
1438
|
//TODO this is pretty similary to processing instructions
|
1355
1439
|
// for views in that we also have to handle the empty case
|
1356
1440
|
//
|
@@ -1407,7 +1491,7 @@ pw_Component.prototype = {
|
|
1407
1491
|
}
|
1408
1492
|
|
1409
1493
|
if (state.length > 0) {
|
1410
|
-
this.view.scope(state[0].scope).
|
1494
|
+
this.view.scope(state[0].scope).setEndpoint(this.endpoint || this).apply(state);
|
1411
1495
|
} else {
|
1412
1496
|
pw.node.breadthFirst(this.view.node, function () {
|
1413
1497
|
if (this.hasAttribute('data-scope')) {
|
@@ -1435,8 +1519,8 @@ pw_Component.prototype = {
|
|
1435
1519
|
}
|
1436
1520
|
},
|
1437
1521
|
|
1438
|
-
|
1439
|
-
this.state.
|
1522
|
+
remove: function (data) {
|
1523
|
+
this.state.remove(data);
|
1440
1524
|
this.transform(this.state.current());
|
1441
1525
|
},
|
1442
1526
|
|
@@ -1470,6 +1554,7 @@ pw.init.register(function () {
|
|
1470
1554
|
pw.socket.init({
|
1471
1555
|
cb: function (socket) {
|
1472
1556
|
window.socket = socket;
|
1557
|
+
pw.component.broadcast('socket:available');
|
1473
1558
|
}
|
1474
1559
|
});
|
1475
1560
|
});
|
@@ -1671,7 +1756,9 @@ pw.instruct = {
|
|
1671
1756
|
});
|
1672
1757
|
},
|
1673
1758
|
|
1674
|
-
// TODO: make this smart and cache results
|
1759
|
+
// TODO: make this smart and cache results, invalidating
|
1760
|
+
// if the websocket connection reconnects (since that means
|
1761
|
+
// the server probably restarted)
|
1675
1762
|
template: function (view, cb) {
|
1676
1763
|
var lookup = {};
|
1677
1764
|
|
@@ -1696,23 +1783,46 @@ pw.instruct = {
|
|
1696
1783
|
});
|
1697
1784
|
},
|
1698
1785
|
|
1699
|
-
perform: function (collection, instructions) {
|
1786
|
+
perform: function (collection, instructions, cb) {
|
1700
1787
|
var self = this;
|
1788
|
+
instructions = instructions || [];
|
1701
1789
|
|
1702
|
-
|
1790
|
+
function instruct (subject, instruction) {
|
1703
1791
|
var method = instruction[0];
|
1704
1792
|
var value = instruction[1];
|
1705
1793
|
var nested = instruction[2];
|
1706
1794
|
|
1795
|
+
// remap instructions to the ring name
|
1796
|
+
if (method === 'with') {
|
1797
|
+
method = 'invoke';
|
1798
|
+
}
|
1799
|
+
|
1800
|
+
if (method === 'for') {
|
1801
|
+
method = 'invokeWithData';
|
1802
|
+
}
|
1803
|
+
|
1707
1804
|
if (collection[method]) {
|
1708
|
-
if (method == '
|
1709
|
-
|
1710
|
-
|
1805
|
+
if (method == 'invoke' || method == 'invokeWithData' || method == 'bind' || method == 'repeat' || method == 'apply' || method == 'version') {
|
1806
|
+
var cbLength = collection.length();
|
1807
|
+
var cbCount = 0;
|
1808
|
+
var nestedCb = function () {
|
1809
|
+
cbCount++;
|
1810
|
+
|
1811
|
+
if (cbCount == cbLength) {
|
1812
|
+
next();
|
1813
|
+
}
|
1814
|
+
}
|
1815
|
+
collection.setEndpoint(self)[method].call(collection, value, function (datum) {
|
1816
|
+
pw.instruct.perform(this, nested[value.indexOf(datum)], nestedCb);
|
1711
1817
|
});
|
1712
1818
|
return;
|
1713
1819
|
} else if (method == 'attrs') {
|
1714
1820
|
self.performAttr(collection.attrs(), nested);
|
1715
1821
|
return;
|
1822
|
+
} else if (method == 'use') {
|
1823
|
+
collection.setEndpoint(self);
|
1824
|
+
collection.use(value, next);
|
1825
|
+
return;
|
1716
1826
|
} else {
|
1717
1827
|
var mutatedViews = collection[method].call(collection, value);
|
1718
1828
|
}
|
@@ -1722,13 +1832,33 @@ pw.instruct = {
|
|
1722
1832
|
}
|
1723
1833
|
|
1724
1834
|
if (nested instanceof Array) {
|
1725
|
-
pw.instruct.perform(mutatedViews, nested);
|
1835
|
+
pw.instruct.perform(mutatedViews, nested, next);
|
1836
|
+
return;
|
1726
1837
|
} else if (mutatedViews) {
|
1727
1838
|
collection = mutatedViews;
|
1728
1839
|
}
|
1729
|
-
});
|
1730
1840
|
|
1731
|
-
|
1841
|
+
next();
|
1842
|
+
};
|
1843
|
+
|
1844
|
+
var i = 0;
|
1845
|
+
function next() {
|
1846
|
+
if (i < instructions.length) {
|
1847
|
+
instruct(collection, instructions[i++]);
|
1848
|
+
} else {
|
1849
|
+
done();
|
1850
|
+
}
|
1851
|
+
};
|
1852
|
+
|
1853
|
+
function done() {
|
1854
|
+
if (cb) {
|
1855
|
+
cb();
|
1856
|
+
} else {
|
1857
|
+
pw.component.findAndInit(collection.node);
|
1858
|
+
}
|
1859
|
+
};
|
1860
|
+
|
1861
|
+
next();
|
1732
1862
|
},
|
1733
1863
|
|
1734
1864
|
performAttr: function (context, attrInstructions) {
|