SlideShare a Scribd company logo
1 of 294
Download to read offline
EtherCalc

 多人即時
協作試算表
EtherCalc
  for Drupal
 多人即時
協作試算表
僅代表個人立場
只講故事
不講程式
概念
只講故事
不講程式
SheetNode.org
SheetNode.org
SheetNode.org




‣ npm install -g ethercalc

‣ ethercalc
 Please connect to: http://0:8000/
⟪開源應用架構⟫

EtherCalc.tw


aosabook.org
緣起
VisiCalc, 1979




Dan Bricklin
哈佛商學院, 1977
哈佛商學院, 1977
哈佛商學院, 1977
哈佛商學院, 1977
哈佛商學院, 1977
最初的願景
最初的願景




 Alto 工作站
最初的願景




         Alto 工作站
滑鼠計算機
最初的願景




         Alto 工作站
滑鼠計算機               頭戴顯示器
最初的願景




         Alto 工作站
滑鼠計算機               頭戴顯示器
=SUM( )   0
10       20    30

     =SUM( )        60
                    30
                    10
                     0
10       20    30

     =SUM( )        60
                    30
                    10
                     0
1977 → 1978
1977 → 1978
1977 → 1978



       +



  Integer BASIC
1978 → 1979
1978 → 1979
  10      20   30
  =SUM(        )    60
1978 → 1979
    A       B    C    D
1   10      20   30

2   =SUM(        )    60
1978 → 1979
    A     B     C    D
1   10    20    30

2   =SUM(A1,B1,C1)   60
1978 → 1979
    A     B     C    D
1   10    20    30

2   =SUM(A1,B1,C1)   60




                     Bob & Dan
1978 → 1979
         A     B     C    D
     1   10    20    30

     2   =SUM(A1,B1,C1)   60


‣ 6 年售出 700,000 套

                          Bob & Dan
1978 → 1979
        A     B     C    D
    1   10    20    30

    2   =SUM(A1,B1,C1)   60


‣ 6 年售出 700,000 套
‣ 「殺手級應用」的始祖
                         Bob & Dan
1981
二十年來
二十年來
二十年來
二十年來
二十年來


  始終如一
“打不開”
“打不開”
“變亂碼”
“打不開”
“變亂碼”
“有病毒!”
維基百科, 2001
維基百科, 2001
維基百科, 2001
wikiCalc, 2005
wikiCalc, 2005
✓ 跨伺服器引用數值。
wikiCalc, 2005
✓ 跨伺服器引用數值。
✓ 保留每個版本,可隨時回復 。
wikiCalc, 2005
✓ 跨伺服器引用數值。
✓ 保留每個版本,可隨時回復 。
✓ 支援純文字、HTML、Wiki 語法。
wikiCalc, 2005
✓ 跨伺服器引用數值。
✓ 保留每個版本,可隨時回復 。
✓ 支援純文字、HTML、Wiki 語法。
✓ 開放源碼!
wikiCalc.pl
wikiCalc.pl
       網站
./wkcdata/sites/Foo
 ./wkcdata/sites/Bar
  ./wkcdata/sites/Baz
wikiCalc.pl
       網站               頁面
./wkcdata/sites/Foo
                        XXX
 ./wkcdata/sites/Bar
  ./wkcdata/sites/Baz   YYY
                        ZZZ
wikiCalc.pl
       網站               頁面
./wkcdata/sites/Foo
                        XXX
 ./wkcdata/sites/Bar
  ./wkcdata/sites/Baz   YYY
                        ZZZ


               儲存格
wikiCalc.pl
       網站               頁面
./wkcdata/sites/Foo
                        XXX
 ./wkcdata/sites/Bar
  ./wkcdata/sites/Baz   YYY
                        ZZZ


               儲存格
    A1: 100
wikiCalc.pl
       網站               頁面
./wkcdata/sites/Foo
                        XXX
 ./wkcdata/sites/Bar
  ./wkcdata/sites/Baz   YYY
                        ZZZ


               儲存格
    A1: 100
    A2: =A1*2
wikiCalc.pl
       網站                 頁面
./wkcdata/sites/Foo
                          XXX
 ./wkcdata/sites/Bar
  ./wkcdata/sites/Baz     YYY
                          ZZZ


               儲存格
    A1: 100 B1: =XXX!C1
    A2: =A1*2
wikiCalc.pl
       網站                 頁面
./wkcdata/sites/Foo
                          XXX
 ./wkcdata/sites/Bar
  ./wkcdata/sites/Baz     YYY
                          ZZZ


               儲存格
    A1: 100 B1: =XXX!C1
    A2: =A1*2
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
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
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
                            跨頁引用
wikiCalc 編輯流程
wikiCalc 編輯流程
   A1: 100
   A2: =A1*2
wikiCalc 編輯流程
   A1: 100
   A2: =A1*2
wikiCalc 編輯流程
     A1: 100
     A2: =A1*2


  POST /
  ajaxsetcell=host:page:A1:300
                                 wikicalc.pl
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>
“載入中…”
“載入中…”
“載入中…”




“C100k” 問題
“載入中…”




“C100k” 問題
打掉重練
打掉重練
SocialCalc, 2006



Dan Bricklin   Ross Mayfield
設計目標
設計目標

‣ 引擎用 JavaScript 重寫。
設計目標

‣ 引擎用 JavaScript 重寫。
‣ 即時編輯及還原/重作。
設計目標

‣ 引擎用 JavaScript 重寫。
‣ 即時編輯及還原/重作。
‣ 能處理十萬個儲存格。
系統架構
系統架構
SocialCalc.js




HTTP Server
系統架構
      SocialCalc.js


GET



      HTTP Server
系統架構
      SocialCalc.js


GET



      HTTP Server
系統架構
      SocialCalc.js


GET   GET



      HTTP Server
系統架構
      SocialCalc.js


GET   GET
       ($)



      HTTP Server
系統架構
      SocialCalc.js

                      PUT
GET   GET
       ($)



      HTTP Server
指令設計模式
指令設計模式
set A1 value n 42
指令設計模式
set A1 value n 42
set A2 formula A1*2
指令設計模式
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
...
指令設計模式
set A1 value n 42
set A2 formula A1*2

‣ 背景處理計算。
指令設計模式
set A1 value n 42
set A2 formula A1*2

‣ 背景處理計算。
‣ 無限次還原重做。
指令設計模式
set A1 value n 42
set A2 formula A1*2

‣ 背景處理計算。
‣ 無限次還原重做。
‣ 鍵盤滑鼠隨時可用!
“社會化” 試算表
“社會化” 試算表
“社會化” 試算表




 評論、按讚、推薦、
    標記、分享、嵌入...
社會物件   人際連結
社會物件   人際連結
社會物件   人際連結
工
CPAL 通用公共授權
CPAL 通用公共授權
  ㊔
BSD, MIT
CPAL 通用公共授權
              ©
  ㊔
BSD, MIT   LGPL, MPL
CPAL 通用公共授權
              ©        ++©
  ㊔
BSD, MIT   LGPL, MPL   GPL
CPAL 通用公共授權
              ©                                         ++©
  ㊔
BSD, MIT   LGPL, MPL                                    GPL
               “ASP
     ”
CPAL 通用公共授權
              ©                                          ++©
  ㊔
BSD, MIT   LGPL, MPL                                      GPL
               “ASP
       ”
                                                        Affero GPL
CPAL 通用公共授權
              ©                                          ++©
  ㊔
BSD, MIT   LGPL, MPL                                      GPL
               “ASP
       ”

             CPAL                                       Affero GPL
CPAL 通用公共授權
              ©                                          ++©
  ㊔
BSD, MIT   LGPL, MPL                                      GPL
               “ASP
       ”

             CPAL                                       Affero GPL
CPAL 通用公共授權
              ©                                          ++©
  ㊔
BSD, MIT   LGPL, MPL                                      GPL
               “ASP
       ”

             CPAL                                       Affero GPL
CPAL 通用公共授權
              ©                                          ++©
  ㊔
BSD, MIT   LGPL, MPL                                      GPL
               “ASP
       ”

             CPAL                                       Affero GPL
Sheetnode, 2008




Karim Ratib
Sheetnode, 2008
              Views + Fields + CCK




Karim Ratib
Sheetnode, 2008
              Views + Fields + CCK



                  SocialCalc.js


Karim Ratib
Sheetnode, 2008
              Views + Fields + CCK



                  SocialCalc.js


Karim Ratib
Sheetnode, 2008
              Views + Fields + CCK



                  SocialCalc.js


Karim Ratib
Sheetnode, 2008
              Views + Fields + CCK



                  SocialCalc.js


Karim Ratib
Sheetnode, 2008
Sheetnode, 2008
I was looking for an open source
equivalent to Google Docs that
would allow tighter integration
with a company's data:
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.”
SheetNode.org
SheetNode.org
SheetNode.org




Views
OLPC, 2008
OLPC, 2008




Luke Closs  Dan
Mesh
網絡
Manusheel
  Gupta




Vijit Singh
SocialCalcActivity.py
                  Gecko/XPCOM
                 SocialCalc.js
                    XoCom.js

                    XoCom.py



Manusheel
  Gupta




Vijit Singh
SocialCalcActivity.py
                                      Gecko/XPCOM
                                     SocialCalc.js
                                        XoCom.js

              set A1 value n 42         XoCom.py



Manusheel
  Gupta




Vijit Singh
SocialCalcActivity.py
                                      Gecko/XPCOM
                                     SocialCalc.js
                                        XoCom.js

              set A1 value n 42         XoCom.py

                                      D-Bus + Telepathy

Manusheel
  Gupta




Vijit Singh
SocialCalcActivity.py
                                      Gecko/XPCOM
                                     SocialCalc.js
                                        XoCom.js

              set A1 value n 42         XoCom.py

                                      D-Bus + Telepathy
                            OLPC Mesh
Manusheel
  Gupta                      網絡廣播




Vijit Singh
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
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
很讚,但是...
很讚,但是...

‣ 漏接訊息無法復原。
很讚,但是...

‣ 漏接訊息無法復原。
‣ 編輯同一格時會衝突。
很讚,但是...

‣ 漏接訊息無法復原。
‣ 編輯同一格時會衝突。
‣ 只能在 OLPC 上使用!
YAPC::Tiny, 2009
EV: 事件驅動
Tatsumaki    EV: 事件驅動




 @miyagawa
Tatsumaki  EV: 事件驅動
        Web::Hippie




 @miyagawa   @clkao
Tatsumaki  EV: 事件驅動
        Web::Hippie
                 Feersum



 @miyagawa   @clkao   @stash
WebSocket 同步編輯
     multiserver.pl

      Web::Hippie
         Plack
        Feersum
        EV/libev
WebSocket 同步編輯
  SpreadsheetControl
                        multiserver.pl

                         Web::Hippie
ScheduleScheetCommand
 set A1 value n 2046        Plack
   RenderSheet
                           Feersum
                           EV/libev
WebSocket 同步編輯
  SpreadsheetControl
                            multiserver.pl

                             Web::Hippie
ScheduleScheetCommand
 set A1 value n 2046            Plack
   RenderSheet
                       傳送      Feersum
                               EV/libev
WebSocket 同步編輯
  SpreadsheetControl
                            multiserver.pl


ScheduleScheetCommand
                             Web::Hippie     群播
 set A1 value n 2046            Plack
   RenderSheet
                       傳送      Feersum
                               EV/libev
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
新增功能
新增功能

✓斷線重連可以復原。
新增功能

✓斷線重連可以復原。
✓顯示別人的游標位置。
新增功能

✓斷線重連可以復原。
✓顯示別人的游標位置。
✓可以在各平台上運行!
新增功能

✓斷線重連可以復原。
✓顯示別人的游標位置。
✓可以在各平台上運行!
更讚了,但是...
更讚了,但是...

‣ 要相信誰的目前狀態?
更讚了,但是...

‣ 要相信誰的目前狀態?
‣ 所有人離線:資料消失?
更讚了,但是...

‣ 要相信誰的目前狀態?
‣ 所有人離線:資料消失?
‣ 重新連接:回播所有指令?
更讚了,但是...

‣ 要相信誰的目前狀態?
‣ 所有人離線:資料消失?
‣ 重新連接:回播所有指令?
打掉重練
打掉重練
YAPC::NA, 2006
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. ”
YAPC::NA, 2006
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. ”
YAPC::NA, 2006
YAPC::NA, 2006
“Because, as we all know,
worse is better, so the worst
scripting language is doomed
to become the best.”
YAPC::NA, 2006
“Because, as we all know,
worse is better, so the worst
scripting language is doomed
to become the best.”

      劣即是夯
JavaScript: 缺點減少
JavaScript: 缺點減少
 CoffeeScript: 標點減半
  cs = (js) - js/2


 Jeremy
Ashkenas
JavaScript: 缺點減少
 CoffeeScript: 標點減半
  cs = (js) - js/2


 Jeremy
Ashkenas
JavaScript: 缺點減少
 CoffeeScript: 標點減半
  cs = (js) - js/2

           “原 JavaScript 行數: 22k。
            重寫過的 CoffeeScript 行數: 5k。
            {async, jsdom, zappa, optimist etc}++”
 Jeremy
Ashkenas
{x,y} = @offset
{x,y} = @offset
var offset = this.offset;
{x,y} = @offset
var offset = this.offset;
var x = offset.x;
{x,y} = @offset
var offset = this.offset;
var x = offset.x;
var y = offset.y;
{x,y} = @offset
var offset = this.offset;
var x = offset.x;
var y = offset.y;

           js2coffee.org
COSCUP, 2011
COSCUP, 2011
COSCUP, 2011




hack
 hack
 hack
 ...
COSCUP, 2011




hack
 hack
 hack
 ...
EtherCalc 系統架構
EtherCalc 系統架構
      main.coffee
 sc.coffee
                 Socket.io
SocialCalc.js
 SocialCalc.js
                 Express
                 Node.js
 db.coffee        EV/libuv
   redis.js       Zappa
EtherCalc 系統架構
      main.coffee
 sc.coffee
                 Socket.io
SocialCalc.js
 SocialCalc.js
                 Express
                 Node.js
 db.coffee        EV/libuv
   redis.js       Zappa



  Redis
 (optional)
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)
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)
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)
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)
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)
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
跨頁即時更新
跨頁即時更新

伺
服
端
跨頁即時更新

伺            客
服            戶
端            端
跨頁即時更新
      ask.log: XXX


伺                    客
服                    戶
端                    端
跨頁即時更新
               ask.log: XXX


伺   log: XXX,snapshot,log
                              客
服                             戶
端                             端
跨頁即時更新
               ask.log: XXX


伺   log: XXX,snapshot,log
                              客
            execute: set A1
服            formula YYY!B2   戶
端                             端
跨頁即時更新
               ask.log: XXX


伺   log: XXX,snapshot,log
                              客
            execute: set A1
服            formula YYY!B2   戶
    recalc: YYY,snapshot
端                             端
跨頁即時更新
               ask.log: XXX


伺   log: XXX,snapshot,log
                              客
            execute: set A1
服            formula YYY!B2   戶
    recalc: YYY,snapshot
端   recalc: YYY,snapshot
                              端
跨頁即時更新
               ask.log: XXX


伺   log: XXX,snapshot,log
                              客
            execute: set A1
服            formula YYY!B2   戶
    recalc: YYY,snapshot
端   recalc: YYY,snapshot
                              端
    recalc: YYY,snapshot
REST 資源界面
REST 資源界面
GET /_/page
PUT /_/page
REST 資源界面
GET /_/page   POST /_/page
PUT /_/page    {commands:[…]}
REST 資源界面
GET /_/page   POST /_/page
PUT /_/page    {commands:[…]}


   GET /_/page/cells/A1
   PUT /_/page/cells/B2
+   =
+   =

+   = Coco
+   =

       +   = Coco

Coco   +   =
stove.on(heat, function() {
stove.on(heat, function() {
    pot.on(boil, function() {
stove.on(heat, function() {
    pot.on(boil, function() {
        rice.on(ready, function(dish) {
stove.on(heat, function() {
    pot.on(boil, function() {
        rice.on(ready, function(dish) {
            setTimeout(function() {
stove.on(heat, function() {
    pot.on(boil, function() {
        rice.on(ready, function(dish) {
            setTimeout(function() {
                dish.serve();
            }, 60000);
stove.on(heat, function() {
    pot.on(boil, function() {
        rice.on(ready, function(dish) {
            setTimeout(function() {
                dish.serve();
            }, 60000);
        });
    });
});
stove.on(heat, function() {
    pot.on(boil, function() {
        rice.on(ready, function(dish) {
            setTimeout(function() {
                dish.serve();
            }, 60000);
        });
    });
});
stove.on(heat, function() {
    pot.on(boil, function() {
        rice.on(ready, function(dish) {
            setTimeout(function() {
                dish.serve();
            }, 60000);
        });
    });
});
stove.on heat, -
stove.on heat, -
    pot.on boil, -
stove.on heat, -
    pot.on boil, -
        rice.on ready, (dish) -
stove.on heat, -
    pot.on boil, -
        rice.on ready, (dish) -
            setTimeout(
stove.on heat, -
    pot.on boil, -
        rice.on ready, (dish) -
            setTimeout(
                - dish.serve()
stove.on heat, -
    pot.on boil, -
        rice.on ready, (dish) -
            setTimeout(
                - dish.serve()
                60000
stove.on heat, -
    pot.on boil, -
        rice.on ready, (dish) -
            setTimeout(
                - dish.serve()
                60000
            )
stove.on heat, -
    pot.on boil, -
        rice.on ready, (dish) -
            setTimeout(
                - dish.serve()
                60000
            )
- stove.on heat
- stove.on heat
- pot.on   boil
- stove.on heat
- pot.on   boil
dish - rice.on ready
- stove.on heat
- pot.on   boil
dish - rice.on ready
- (`setTimeout` 60000)
- stove.on heat
- pot.on   boil
dish - rice.on ready
- (`setTimeout` 60000)
dish.serve!
- stove.on heat
- pot.on   boil
dish - rice.on ready
- (`setTimeout` 60000)
dish.serve!
OSDC.tw, 2012
OSDC.tw, 2012
OSDC.tw, 2012
OSDC.tw, 2012
哪來的「高風亮節」…
哪來的「高風亮節」…

只是沒寫過
Drupal 模組。
雖然 Isis 架過
許多 Drupal 網站
我也幫忙改了一些…
雖然 Isis 架過
許多 Drupal 網站
我也幫忙改了一些…
雖然 Isis 架過
許多 Drupal 網站
我也幫忙改了一些…
雖然 Isis 架過
許多 Drupal 網站
我也幫忙改了一些…
可是我對架構

完全沒有概念。
可是我對架構

完全沒有概念。
⟪開源之樂⟫, 2012. 7. 1.
⟪開源之樂⟫, 2012. 7. 1.
⟪開源之樂⟫, 2012. 7. 1.
⟪開源之樂⟫, 2012. 7. 1.


     “內容過於抽象。”
⟪開源之樂⟫, 2012. 7. 1.


     “內容過於抽象。”
     “這跟 Drupal
      到底有何關係?”
2012. 7. 2.
2012. 7. 2.
“你還是把
EtherCalc
 for Drupal
  寫出來,
比較有意義。”
2012. 7. 2.
“你還是把
EtherCalc
 for Drupal
  寫出來,
比較有意義。”
2012. 7. 2.
“你還是把
EtherCalc
 for Drupal
  寫出來,
比較有意義。”
2012. 7. 3.
2012. 7. 3.

感謝 Karim 幫忙
2012. 7. 3.

 感謝 Karim 幫忙

 一個早上
 就寫完了。
/**
 *
 * 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,
  ));
}
/**
 *
 * 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,
  ));
}
/**
  * 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#');
   }
}
/**
  * 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#');
   }
}
2012. 7. 4.
2012. 7. 4.

More Related Content

Similar to EtherCalc for Drupal

igdshare 110220: LuaJIT intro
igdshare 110220: LuaJIT introigdshare 110220: LuaJIT intro
igdshare 110220: LuaJIT introigdshare
 
手把手教你把Vim改装成一个IDE编程环境(图文)
手把手教你把Vim改装成一个IDE编程环境(图文)手把手教你把Vim改装成一个IDE编程环境(图文)
手把手教你把Vim改装成一个IDE编程环境(图文)King Hom
 
Groovy Introduction for Java Programmer
Groovy Introduction for Java ProgrammerGroovy Introduction for Java Programmer
Groovy Introduction for Java ProgrammerLi Ding
 
美团点评技术沙龙05 - 前后端联调方案探索与应用
美团点评技术沙龙05 - 前后端联调方案探索与应用美团点评技术沙龙05 - 前后端联调方案探索与应用
美团点评技术沙龙05 - 前后端联调方案探索与应用美团点评技术团队
 
IoTDB Quick Start
IoTDB Quick StartIoTDB Quick Start
IoTDB Quick StartJialinQiao
 
爲何開源 why open source
爲何開源 why open source爲何開源 why open source
爲何開源 why open sourceKenson Chou
 
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践Jackson Tian
 
搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流bj
 
搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流jondynet
 
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)OpenFoundry
 
深入浅出Netty l.t
深入浅出Netty   l.t深入浅出Netty   l.t
深入浅出Netty l.toleone
 
Android C Library: Bionic 成長計畫
Android C Library: Bionic 成長計畫Android C Library: Bionic 成長計畫
Android C Library: Bionic 成長計畫Kito Cheng
 

Similar to EtherCalc for Drupal (15)

igdshare 110220: LuaJIT intro
igdshare 110220: LuaJIT introigdshare 110220: LuaJIT intro
igdshare 110220: LuaJIT intro
 
手把手教你把Vim改装成一个IDE编程环境(图文)
手把手教你把Vim改装成一个IDE编程环境(图文)手把手教你把Vim改装成一个IDE编程环境(图文)
手把手教你把Vim改装成一个IDE编程环境(图文)
 
Groovy Introduction for Java Programmer
Groovy Introduction for Java ProgrammerGroovy Introduction for Java Programmer
Groovy Introduction for Java Programmer
 
from Source to Binary: How GNU Toolchain Works
from Source to Binary: How GNU Toolchain Worksfrom Source to Binary: How GNU Toolchain Works
from Source to Binary: How GNU Toolchain Works
 
美团点评技术沙龙05 - 前后端联调方案探索与应用
美团点评技术沙龙05 - 前后端联调方案探索与应用美团点评技术沙龙05 - 前后端联调方案探索与应用
美团点评技术沙龙05 - 前后端联调方案探索与应用
 
IoTDB Quick Start
IoTDB Quick StartIoTDB Quick Start
IoTDB Quick Start
 
爲何開源 why open source
爲何開源 why open source爲何開源 why open source
爲何開源 why open source
 
fis
fisfis
fis
 
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
 
搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流
 
搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流搜狐Pv insight(py)技术交流
搜狐Pv insight(py)技术交流
 
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
 
深入浅出Netty l.t
深入浅出Netty   l.t深入浅出Netty   l.t
深入浅出Netty l.t
 
Android C Library: Bionic 成長計畫
Android C Library: Bionic 成長計畫Android C Library: Bionic 成長計畫
Android C Library: Bionic 成長計畫
 
Intro to svn
Intro to svnIntro to svn
Intro to svn
 

More from Audrey Tang

Social Innovation & Digital Transformation
Social Innovation & Digital TransformationSocial Innovation & Digital Transformation
Social Innovation & Digital TransformationAudrey Tang
 
Stories from the Future of Democracy
Stories from the Future of DemocracyStories from the Future of Democracy
Stories from the Future of DemocracyAudrey Tang
 
TEDxTaipei 2017: 社會企業
TEDxTaipei 2017: 社會企業TEDxTaipei 2017: 社會企業
TEDxTaipei 2017: 社會企業Audrey Tang
 
唐鳳政務委員業務工作報告
唐鳳政務委員業務工作報告唐鳳政務委員業務工作報告
唐鳳政務委員業務工作報告Audrey Tang
 
資訊服務採購契約範本 修正明細對照 1060713
資訊服務採購契約範本 修正明細對照 1060713資訊服務採購契約範本 修正明細對照 1060713
資訊服務採購契約範本 修正明細對照 1060713Audrey Tang
 
服務型智慧政府推動計畫 v9
服務型智慧政府推動計畫 v9服務型智慧政府推動計畫 v9
服務型智慧政府推動計畫 v9Audrey Tang
 
共通性應用程式介面規範
共通性應用程式介面規範共通性應用程式介面規範
共通性應用程式介面規範Audrey Tang
 
打造一站式的防救災資訊整合平臺
打造一站式的防救災資訊整合平臺打造一站式的防救災資訊整合平臺
打造一站式的防救災資訊整合平臺Audrey Tang
 
開放政府聯絡人第11次協作會議簡報
開放政府聯絡人第11次協作會議簡報開放政府聯絡人第11次協作會議簡報
開放政府聯絡人第11次協作會議簡報Audrey Tang
 
第7次協作會議會後會簡報v6.0
第7次協作會議會後會簡報v6.0第7次協作會議會後會簡報v6.0
第7次協作會議會後會簡報v6.0Audrey Tang
 
臨時動議:社會企業連繫會議分組
臨時動議:社會企業連繫會議分組臨時動議:社會企業連繫會議分組
臨時動議:社會企業連繫會議分組Audrey Tang
 
議程及歷次列管表
議程及歷次列管表議程及歷次列管表
議程及歷次列管表Audrey Tang
 
討論案一:中、南、東部在地社企會談規劃情形
討論案一:中、南、東部在地社企會談規劃情形討論案一:中、南、東部在地社企會談規劃情形
討論案一:中、南、東部在地社企會談規劃情形Audrey Tang
 
報告案四之一:創櫃板協助社會企業籌資之推動現況
報告案四之一:創櫃板協助社會企業籌資之推動現況報告案四之一:創櫃板協助社會企業籌資之推動現況
報告案四之一:創櫃板協助社會企業籌資之推動現況Audrey Tang
 
報告案四之二:國發基金運用資金協助社會發展辦理方式
報告案四之二:國發基金運用資金協助社會發展辦理方式報告案四之二:國發基金運用資金協助社會發展辦理方式
報告案四之二:國發基金運用資金協助社會發展辦理方式Audrey Tang
 
報告案二:組團參加2017年社會企業世界論壇辦理進度報告
報告案二:組團參加2017年社會企業世界論壇辦理進度報告報告案二:組團參加2017年社會企業世界論壇辦理進度報告
報告案二:組團參加2017年社會企業世界論壇辦理進度報告Audrey Tang
 
報告案三 :SEWF申辦2019進度說明
報告案三 :SEWF申辦2019進度說明報告案三 :SEWF申辦2019進度說明
報告案三 :SEWF申辦2019進度說明Audrey Tang
 
2017-06-17 臺灣網路治理論壇
2017-06-17 臺灣網路治理論壇2017-06-17 臺灣網路治理論壇
2017-06-17 臺灣網路治理論壇Audrey Tang
 
行政院數位國家創新經濟推動小組設置要點
行政院數位國家創新經濟推動小組設置要點行政院數位國家創新經濟推動小組設置要點
行政院數位國家創新經濟推動小組設置要點Audrey Tang
 
DIGI⁺ 數位政府
DIGI⁺ 數位政府DIGI⁺ 數位政府
DIGI⁺ 數位政府Audrey Tang
 

More from Audrey Tang (20)

Social Innovation & Digital Transformation
Social Innovation & Digital TransformationSocial Innovation & Digital Transformation
Social Innovation & Digital Transformation
 
Stories from the Future of Democracy
Stories from the Future of DemocracyStories from the Future of Democracy
Stories from the Future of Democracy
 
TEDxTaipei 2017: 社會企業
TEDxTaipei 2017: 社會企業TEDxTaipei 2017: 社會企業
TEDxTaipei 2017: 社會企業
 
唐鳳政務委員業務工作報告
唐鳳政務委員業務工作報告唐鳳政務委員業務工作報告
唐鳳政務委員業務工作報告
 
資訊服務採購契約範本 修正明細對照 1060713
資訊服務採購契約範本 修正明細對照 1060713資訊服務採購契約範本 修正明細對照 1060713
資訊服務採購契約範本 修正明細對照 1060713
 
服務型智慧政府推動計畫 v9
服務型智慧政府推動計畫 v9服務型智慧政府推動計畫 v9
服務型智慧政府推動計畫 v9
 
共通性應用程式介面規範
共通性應用程式介面規範共通性應用程式介面規範
共通性應用程式介面規範
 
打造一站式的防救災資訊整合平臺
打造一站式的防救災資訊整合平臺打造一站式的防救災資訊整合平臺
打造一站式的防救災資訊整合平臺
 
開放政府聯絡人第11次協作會議簡報
開放政府聯絡人第11次協作會議簡報開放政府聯絡人第11次協作會議簡報
開放政府聯絡人第11次協作會議簡報
 
第7次協作會議會後會簡報v6.0
第7次協作會議會後會簡報v6.0第7次協作會議會後會簡報v6.0
第7次協作會議會後會簡報v6.0
 
臨時動議:社會企業連繫會議分組
臨時動議:社會企業連繫會議分組臨時動議:社會企業連繫會議分組
臨時動議:社會企業連繫會議分組
 
議程及歷次列管表
議程及歷次列管表議程及歷次列管表
議程及歷次列管表
 
討論案一:中、南、東部在地社企會談規劃情形
討論案一:中、南、東部在地社企會談規劃情形討論案一:中、南、東部在地社企會談規劃情形
討論案一:中、南、東部在地社企會談規劃情形
 
報告案四之一:創櫃板協助社會企業籌資之推動現況
報告案四之一:創櫃板協助社會企業籌資之推動現況報告案四之一:創櫃板協助社會企業籌資之推動現況
報告案四之一:創櫃板協助社會企業籌資之推動現況
 
報告案四之二:國發基金運用資金協助社會發展辦理方式
報告案四之二:國發基金運用資金協助社會發展辦理方式報告案四之二:國發基金運用資金協助社會發展辦理方式
報告案四之二:國發基金運用資金協助社會發展辦理方式
 
報告案二:組團參加2017年社會企業世界論壇辦理進度報告
報告案二:組團參加2017年社會企業世界論壇辦理進度報告報告案二:組團參加2017年社會企業世界論壇辦理進度報告
報告案二:組團參加2017年社會企業世界論壇辦理進度報告
 
報告案三 :SEWF申辦2019進度說明
報告案三 :SEWF申辦2019進度說明報告案三 :SEWF申辦2019進度說明
報告案三 :SEWF申辦2019進度說明
 
2017-06-17 臺灣網路治理論壇
2017-06-17 臺灣網路治理論壇2017-06-17 臺灣網路治理論壇
2017-06-17 臺灣網路治理論壇
 
行政院數位國家創新經濟推動小組設置要點
行政院數位國家創新經濟推動小組設置要點行政院數位國家創新經濟推動小組設置要點
行政院數位國家創新經濟推動小組設置要點
 
DIGI⁺ 數位政府
DIGI⁺ 數位政府DIGI⁺ 數位政府
DIGI⁺ 數位政府
 

EtherCalc for Drupal