More Related Content Similar to EtherCalc for Drupal (15) More from Audrey Tang (20) EtherCalc for Drupal20. 最初的願景
Alto 工作站
滑鼠計算機 頭戴顯示器
21. 最初的願景
Alto 工作站
滑鼠計算機 頭戴顯示器
25. 10 20 30
=SUM( ) 60
30
10
0
26. 10 20 30
=SUM( ) 60
30
10
0
34. 1978 → 1979
A B C D
1 10 20 30
2 =SUM(A1,B1,C1) 60
Bob & Dan
35. 1978 → 1979
A B C D
1 10 20 30
2 =SUM(A1,B1,C1) 60
‣ 6 年售出 700,000 套
Bob & Dan
36. 1978 → 1979
A B C D
1 10 20 30
2 =SUM(A1,B1,C1) 60
‣ 6 年售出 700,000 套
‣ 「殺手級應用」的始祖
Bob & Dan
62. wikiCalc.pl
網站
./wkcdata/sites/Foo
./wkcdata/sites/Bar
./wkcdata/sites/Baz
63. wikiCalc.pl
網站 頁面
./wkcdata/sites/Foo
XXX
./wkcdata/sites/Bar
./wkcdata/sites/Baz YYY
ZZZ
64. wikiCalc.pl
網站 頁面
./wkcdata/sites/Foo
XXX
./wkcdata/sites/Bar
./wkcdata/sites/Baz YYY
ZZZ
儲存格
65. wikiCalc.pl
網站 頁面
./wkcdata/sites/Foo
XXX
./wkcdata/sites/Bar
./wkcdata/sites/Baz YYY
ZZZ
儲存格
A1: 100
66. wikiCalc.pl
網站 頁面
./wkcdata/sites/Foo
XXX
./wkcdata/sites/Bar
./wkcdata/sites/Baz YYY
ZZZ
儲存格
A1: 100
A2: =A1*2
67. wikiCalc.pl
網站 頁面
./wkcdata/sites/Foo
XXX
./wkcdata/sites/Bar
./wkcdata/sites/Baz YYY
ZZZ
儲存格
A1: 100 B1: =XXX!C1
A2: =A1*2
68. wikiCalc.pl
網站 頁面
./wkcdata/sites/Foo
XXX
./wkcdata/sites/Bar
./wkcdata/sites/Baz YYY
ZZZ
儲存格
A1: 100 B1: =XXX!C1
A2: =A1*2
69. wikiCalc.pl
網站 頁面
./wkcdata/sites/Foo
XXX
./wkcdata/sites/Bar
./wkcdata/sites/Baz YYY
ZZZ
儲存格
A1: 100 B1: =XXX!C1
A2: =A1*2 B2: =YYY!D2
70. wikiCalc.pl
網站 頁面
./wkcdata/sites/Foo
XXX
./wkcdata/sites/Bar
./wkcdata/sites/Baz YYY
ZZZ
儲存格
A1: 100 B1: =XXX!C1
A2: =A1*2 B2: =YYY!D2
71. wikiCalc.pl
網站 頁面
./wkcdata/sites/Foo
XXX
./wkcdata/sites/Bar
./wkcdata/sites/Baz YYY
ZZZ
儲存格
A1: 100 B1: =XXX!C1
A2: =A1*2 B2: =YYY!D2
跨頁引用
75. wikiCalc 編輯流程
A1: 100
A2: =A1*2
POST /
ajaxsetcell=host:page:A1:300
wikicalc.pl
76. wikiCalc 編輯流程
A1: 100
A2: =A1*2
POST /
ajaxsetcell=host:page:A1:300
wikicalc.pl
200 OK
<?xml version="1.0"?>
<root><![CDATA[
A1:v:300:300:right:1:1::
A2:f:600:A1*2:right:1:1::
]]></root>
91. 系統架構
SocialCalc.js
GET
HTTP Server
92. 系統架構
SocialCalc.js
GET
HTTP Server
93. 系統架構
SocialCalc.js
GET GET
HTTP Server
94. 系統架構
SocialCalc.js
GET GET
($)
HTTP Server
95. 系統架構
SocialCalc.js
PUT
GET GET
($)
HTTP Server
99. 指令設計模式
set A1 value n 42
set A2 formula A1*2
merge A1:B2
cut A3
paste A4
sort A1:B9 A up B down
set sheet defaultcolor blue
...
134. Sheetnode, 2008
I was looking for an open source
equivalent to Google Docs that
would allow tighter integration
with a company's data:
135. Sheetnode, 2008
I was looking for an open source
equivalent to Google Docs that
would allow tighter integration
with a company's data:
“Real-time reports,
created out of Drupal data.”
147. SocialCalcActivity.py
Gecko/XPCOM
SocialCalc.js
XoCom.js
set A1 value n 42 XoCom.py
Manusheel
Gupta
Vijit Singh
148. SocialCalcActivity.py
Gecko/XPCOM
SocialCalc.js
XoCom.js
set A1 value n 42 XoCom.py
D-Bus + Telepathy
Manusheel
Gupta
Vijit Singh
149. SocialCalcActivity.py
Gecko/XPCOM
SocialCalc.js
XoCom.js
set A1 value n 42 XoCom.py
D-Bus + Telepathy
OLPC Mesh
Manusheel
Gupta 網絡廣播
Vijit Singh
150. SocialCalcActivity.py
Gecko/XPCOM
SocialCalc.js
XoCom.js
set A1 value n 42 XoCom.py
D-Bus + Telepathy
OLPC Mesh
Manusheel
Gupta 網絡廣播
D-Bus + Telepathy
Gecko/XPCOM
SocialCalc.js
XoCom.js
XoCom.py
Vijit Singh SocialCalcActivity.py
151. SocialCalcActivity.py
Gecko/XPCOM
SocialCalc.js
XoCom.js
set A1 value n 42 XoCom.py
D-Bus + Telepathy
OLPC Mesh
Manusheel
Gupta 網絡廣播
D-Bus + Telepathy
Gecko/XPCOM
set A1 value n 42
SocialCalc.js
XoCom.js
XoCom.py
Vijit Singh SocialCalcActivity.py
160. Tatsumaki EV: 事件驅動
Web::Hippie
Feersum
@miyagawa @clkao @stash
162. WebSocket 同步編輯
SpreadsheetControl
multiserver.pl
Web::Hippie
ScheduleScheetCommand
set A1 value n 2046 Plack
RenderSheet
Feersum
EV/libev
163. WebSocket 同步編輯
SpreadsheetControl
multiserver.pl
Web::Hippie
ScheduleScheetCommand
set A1 value n 2046 Plack
RenderSheet
傳送 Feersum
EV/libev
164. WebSocket 同步編輯
SpreadsheetControl
multiserver.pl
ScheduleScheetCommand
Web::Hippie 群播
set A1 value n 2046 Plack
RenderSheet
傳送 Feersum
EV/libev
165. WebSocket 同步編輯
SpreadsheetControl
multiserver.pl
ScheduleScheetCommand
Web::Hippie 群播
set A1 value n 2046 Plack
ScheduleScheetCommand
RenderSheet
傳送 Feersum set A1 value n 2046
(isRemote = true)
EV/libev
RenderSheet
180. YAPC::NA, 2006
“I think, but I cannot prove, that by
the next year JavaScript 2.0 will
bootstrap itself, complete self
hosting, compile back to JavaScript,
and replace Ruby as the Next Big
Thing in all environments. ”
182. YAPC::NA, 2006
“JavaScript will become the common
backend for all dynamic languages,
and so you can write Perl to run in the
browser, on the server, and inside
databases, all with the same set of
development tools. ”
192. JavaScript: 缺點減少
CoffeeScript: 標點減半
cs = (js) - js/2
“原 JavaScript 行數: 22k。
重寫過的 CoffeeScript 行數: 5k。
{async, jsdom, zappa, optimist etc}++”
Jeremy
Ashkenas
198. {x,y} = @offset
var offset = this.offset;
var x = offset.x;
var y = offset.y;
js2coffee.org
210. EtherCalc 系統架構
main.coffee
sc.coffee
Socket.io
SocialCalc.js
SocialCalc.js
Express
Node.js
db.coffee EV/libuv
redis.js Zappa
211. EtherCalc 系統架構
main.coffee
sc.coffee
Socket.io
SocialCalc.js
SocialCalc.js
Express
Node.js
db.coffee EV/libuv
redis.js Zappa
Redis
(optional)
212. EtherCalc 系統架構
main.coffee
sc.coffee
Socket.io
SocialCalc.js
SocialCalc.js
Express
Node.js
db.coffee EV/libuv player.coffee
redis.js Zappa SocialCalc.js
SocialCalc.js
Redis
(optional)
213. EtherCalc 系統架構
main.coffee
sc.coffee GET snapshot
Socket.io
SocialCalc.js
SocialCalc.js LRANGE log
Express
Node.js
db.coffee EV/libuv player.coffee
redis.js Zappa SocialCalc.js
SocialCalc.js
Redis
(optional)
214. EtherCalc 系統架構
main.coffee
sc.coffee GET snapshot
Socket.io
SocialCalc.js
SocialCalc.js LRANGE log
Express
Node.js
db.coffee EV/libuv player.coffee
redis.js Zappa SocialCalc.js
SocialCalc.js
RPUSH log cmd
Redis
(optional)
215. EtherCalc 系統架構
main.coffee
sc.coffee GET snapshot
Socket.io
SocialCalc.js
SocialCalc.js LRANGE log
Express
Node.js
db.coffee EV/libuv player.coffee
redis.js Zappa SocialCalc.js
SocialCalc.js
RPUSH log cmd
Redis
(optional)
216. EtherCalc 系統架構
main.coffee
sc.coffee GET snapshot
Socket.io
SocialCalc.js
SocialCalc.js LRANGE log
Express
Node.js
db.coffee EV/libuv player.coffee
redis.js Zappa SocialCalc.js
SocialCalc.js
RPUSH log cmd
Redis
(optional)
217. EtherCalc 系統架構
main.coffee
sc.coffee GET snapshot
Socket.io
SocialCalc.js
SocialCalc.js LRANGE log
Express
Node.js
db.coffee EV/libuv player.coffee
redis.js Zappa SocialCalc.js
SocialCalc.js
Redis DEL log RPUSH log cmd
(optional) SET snapshot snapshot
221. 跨頁即時更新
ask.log: XXX
伺 客
服 戶
端 端
222. 跨頁即時更新
ask.log: XXX
伺 log: XXX,snapshot,log
客
服 戶
端 端
223. 跨頁即時更新
ask.log: XXX
伺 log: XXX,snapshot,log
客
execute: set A1
服 formula YYY!B2 戶
端 端
224. 跨頁即時更新
ask.log: XXX
伺 log: XXX,snapshot,log
客
execute: set A1
服 formula YYY!B2 戶
recalc: YYY,snapshot
端 端
225. 跨頁即時更新
ask.log: XXX
伺 log: XXX,snapshot,log
客
execute: set A1
服 formula YYY!B2 戶
recalc: YYY,snapshot
端 recalc: YYY,snapshot
端
226. 跨頁即時更新
ask.log: XXX
伺 log: XXX,snapshot,log
客
execute: set A1
服 formula YYY!B2 戶
recalc: YYY,snapshot
端 recalc: YYY,snapshot
端
recalc: YYY,snapshot
230. REST 資源界面
GET /_/page POST /_/page
PUT /_/page {commands:[…]}
GET /_/page/cells/A1
PUT /_/page/cells/B2
234. + =
+ = Coco
Coco + =
240. stove.on(heat, function() {
pot.on(boil, function() {
rice.on(ready, function(dish) {
setTimeout(function() {
dish.serve();
}, 60000);
241. stove.on(heat, function() {
pot.on(boil, function() {
rice.on(ready, function(dish) {
setTimeout(function() {
dish.serve();
}, 60000);
});
});
});
242. stove.on(heat, function() {
pot.on(boil, function() {
rice.on(ready, function(dish) {
setTimeout(function() {
dish.serve();
}, 60000);
});
});
});
243. stove.on(heat, function() {
pot.on(boil, function() {
rice.on(ready, function(dish) {
setTimeout(function() {
dish.serve();
}, 60000);
});
});
});
249. stove.on heat, -
pot.on boil, -
rice.on ready, (dish) -
setTimeout(
- dish.serve()
250. stove.on heat, -
pot.on boil, -
rice.on ready, (dish) -
setTimeout(
- dish.serve()
60000
251. stove.on heat, -
pot.on boil, -
rice.on ready, (dish) -
setTimeout(
- dish.serve()
60000
)
252. stove.on heat, -
pot.on boil, -
rice.on ready, (dish) -
setTimeout(
- dish.serve()
60000
)
258. - stove.on heat
- pot.on boil
dish - rice.on ready
- (`setTimeout` 60000)
dish.serve!
259. - stove.on heat
- pot.on boil
dish - rice.on ready
- (`setTimeout` 60000)
dish.serve!
288. /**
*
* Implements hook_menu().
*
* In sheetnode_ethercalc_menu.info:
* configure = admin/config/content/sheetnode/ethercalc
*
*/
function sheetnode_ethercalc_menu() {
array('admin/config/content/sheetnode/ethercalc' = array(
'title' = 'EtherCalc',
'access arguments' = array('administer site configuration'),
'page callback' = 'drupal_get_form',
'page arguments' = array('_sheetnode_ethercalc_settings'),
'description' = 'Administer settings for EtherCalc.',
'type' = MENU_LOCAL_TASK,
));
}
289. /**
*
* Implements hook_menu().
*
* In sheetnode_ethercalc_menu.info:
* configure = admin/config/content/sheetnode/ethercalc
*
*/
function sheetnode_ethercalc_menu() {
array('admin/config/content/sheetnode/ethercalc' = array(
'title' = 'EtherCalc',
'access arguments' = array('administer site configuration'),
'page callback' = 'drupal_get_form',
'page arguments' = array('_sheetnode_ethercalc_settings'),
'description' = 'Administer settings for EtherCalc.',
'type' = MENU_LOCAL_TASK,
));
}
290. /**
* Implements hook_sheetnode_plugins().
*/
function sheetnode_ethercalc_sheetnode_plugins(
$value, $save_element, $context
) {
// Only turn on Ethercalc if we're editing the node.
if (!empty($save_element)) {
$ethercalc_host = variable_get('sheetnode_ethercalc_host', '');
$ethercalc_port = variable_get('sheetnode_ethercalc_port', '8000');
$ethercalc_path = …;
drupal_add_js($ethercalc_path . '/socket.io/socket.io.js#');
drupal_add_js($ethercalc_path . '/zappa/zappa.js#');
drupal_add_js($ethercalc_path . '/static/md5.js#');
drupal_add_js($ethercalc_path . '/player/broadcast.js#');
drupal_add_js($ethercalc_path . '/player/main.js#');
}
}
291. /**
* Implements hook_sheetnode_plugins().
*/
function sheetnode_ethercalc_sheetnode_plugins(
$value, $save_element, $context
) {
// Only turn on Ethercalc if we're editing the node.
if (!empty($save_element)) {
$ethercalc_host = variable_get('sheetnode_ethercalc_host', '');
$ethercalc_port = variable_get('sheetnode_ethercalc_port', '8000');
$ethercalc_path = …;
drupal_add_js($ethercalc_path . '/socket.io/socket.io.js#');
drupal_add_js($ethercalc_path . '/zappa/zappa.js#');
drupal_add_js($ethercalc_path . '/static/md5.js#');
drupal_add_js($ethercalc_path . '/player/broadcast.js#');
drupal_add_js($ethercalc_path . '/player/main.js#');
}
}