
เชธเชพเชฎเชพเชจเซเชฏ "เชเซเชฒเชพเชฏเชจเซเช-เชธเชฐเซเชตเชฐ" เชเชฐเซเชเชฟเชเซเชเซเชเชฐเชฅเซ เชตเชฟเชชเชฐเซเชค, เชตเชฟเชเซเชจเซเชฆเซเชฐเชฟเชค เชเชชเซเชฒเชฟเชเซเชถเชจเซ เชฒเชพเชเซเชทเชฃเชฟเชเชคเชพ เชงเชฐเชพเชตเซ เชเซ:
- เชฏเซเชเชฐ เชฒเซเชเซเชจ เช เชจเซ เชชเชพเชธเชตเชฐเซเชก เชธเชพเชฅเซ เชกเซเชเชพเชฌเซเช เชธเซเชเซเชฐ เชเชฐเชตเชพเชจเซ เชเชฐเซเชฐ เชจเชฅเซ. เชเชเซเชธเซเชธ เชฎเชพเชนเชฟเชคเซ เชซเชเซเชค เชตเชชเชฐเชพเชถเชเชฐเซเชคเชพเช เชฆเซเชตเชพเชฐเชพ เช เชธเชเชเซเชฐเชนเชฟเชค เชเชฐเชตเชพเชฎเชพเช เชเชตเซ เชเซ, เช เชจเซ เชคเซเชฎเชจเซ เช เชงเชฟเชเซเชคเชคเชพเชจเซ เชชเซเชทเซเชเชฟ เชชเซเชฐเซเชเซเชเซเชฒ เชธเซเชคเชฐเซ เชฅเชพเชฏ เชเซ.
- เชธเชฐเซเชตเชฐเชจเซ เชเชชเชฏเซเช เชเชฐเชตเชพเชจเซ เชเชฐเซเชฐ เชจเชฅเซ. เชเชชเซเชฒเชฟเชเซเชถเชจ เชฒเซเชเชฟเช เชฌเซเชฒเซเชเชเซเชจ เชจเซเชเชตเชฐเซเช เชชเชฐ เชเชเซเชเชฟเชเซเชฏเซเช เชเชฐเซ เชถเชเชพเชฏ เชเซ, เชเซเชฏเชพเช เชเชฐเซเชฐเซ เชฎเชพเชคเซเชฐเชพเชฎเชพเช เชกเซเชเชพ เชธเซเชเซเชฐ เชเชฐเชตเชพเชจเซเช เชถเชเซเชฏ เชเซ.
เชตเชชเชฐเชพเชถเชเชฐเซเชคเชพ เชเซ เชฎเชพเชเซ 2 เชชเซเชฐเชฎเชพเชฃเชฎเชพเช เชธเชฒเชพเชฎเชค เชธเซเชเซเชฐเซเช เชเซ - เชนเชพเชฐเซเชกเชตเซเชฐ เชตเซเชฒเซเชเซเชธ เช เชจเซ เชฌเซเชฐเชพเชเชเชฐ เชเชเซเชธเซเชเซเชจเซเชถเชจเซเชธ. เชนเชพเชฐเซเชกเชตเซเชฐ เชตเซเชฒเซเชเซเชธ เชฎเซเชเชพเชญเชพเชเซ เช เชคเซเชฏเชเชค เชธเซเชฐเชเซเชทเชฟเชค เชเซ, เชชเชฐเชเชคเซ เชตเชพเชชเชฐเชตเชพ เชฎเชพเชเซ เชฎเซเชถเซเชเซเชฒ เชเซ เช เชจเซ เชฎเชซเชคเชฅเซ เชฆเซเชฐ เชเซ, เชชเชฐเชเชคเซ เชฌเซเชฐเชพเชเชเชฐ เชเชเซเชธเซเชเซเชจเซเชถเชจเซเชธ เชธเชฒเชพเชฎเชคเซ เช เชจเซ เชเชชเชฏเซเชเชฎเชพเช เชธเชฐเชณเชคเชพเชจเซเช เชธเชเชชเซเชฐเซเชฃ เชธเชเชฏเซเชเชจ เชเซ, เช เชจเซ เช เชเชคเชฟเชฎ เชตเชชเชฐเชพเชถเชเชฐเซเชคเชพเช เชฎเชพเชเซ เชธเชเชชเซเชฐเซเชฃเชชเชฃเซ เชฎเชซเชค เชชเชฃ เชนเซเช เชถเชเซ เชเซ.
เช เชฌเชงเชพเชจเซ เชงเซเชฏเชพเชจเชฎเชพเช เชฐเชพเชเซเชจเซ, เช
เชฎเซ เชตเซเชฏเชตเชนเชพเชฐเซ เช
เชจเซ เชนเชธเซเชคเชพเชเซเชทเชฐ เชธเชพเชฅเซ เชเชพเชฎ เชเชฐเชตเชพ เชฎเชพเชเซ เชเช เชธเชฐเชณ API เชชเซเชฐเชฆเชพเชจ เชเชฐเซเชจเซ เชตเชฟเชเซเชจเซเชฆเซเชฐเชฟเชค เชเชชเซเชฒเชฟเชเซเชถเชจเชจเชพ เชตเชฟเชเชพเชธเชจเซ เชธเชฐเชณ เชฌเชจเชพเชตเซ เชคเซเชตเซเช เชธเซเชฅเซ เชธเซเชฐเชเซเชทเชฟเชค เชเชเซเชธเซเชเซเชเชถเชจ เชฌเชจเชพเชตเชตเชพ เชฎเชพเชเซเช เชเซเช.
เช
เชฎเซ เชคเชฎเชจเซ เชจเซเชเซ เช เช
เชจเซเชญเชต เชตเชฟเชถเซ เชเชฃเชพเชตเซเชถเซเช.
เชฒเซเชเชฎเชพเช เชเซเชก เชเชฆเชพเชนเชฐเชฃเซ เช เชจเซ เชธเซเชเซเชฐเซเชจเชถเซเชเซเชธ เชธเชพเชฅเซ, เชฌเซเชฐเชพเชเชเชฐ เชเชเซเชธเซเชเซเชเชถเชจ เชเซเชตเซ เชฐเซเชคเซ เชฒเชเชตเซเช เชคเซเชจเชพ เชชเชฐ เชชเชเชฒเซเช-เชฆเชฐ-เชชเชเชฒเชพเช เชธเซเชเชจเซ เชนเชถเซ. เชคเชฎเซ เชฌเชงเชพ เชเซเชก เชถเซเชงเซ เชถเชเซ เชเซ . เชฆเชฐเซเช เชชเซเชฐเชคเชฟเชฌเชฆเซเชงเชคเชพ เชคเชพเชฐเซเชเชฟเช เชฐเซเชคเซ เช เชฒเซเชเชจเชพ เชตเชฟเชญเชพเชเชจเซ เช เชจเซเชฐเซเชช เชเซ.
เชฌเซเชฐเชพเชเชเชฐ เชเชเซเชธเซเชเซเชจเซเชถเชจเซเชธเชจเซ เชธเชเชเซเชทเชฟเชชเซเชค เชเชคเชฟเชนเชพเชธ
เชฌเซเชฐเชพเชเชเชฐ เชเชเซเชธเซเชเซเชเชถเชจ เชฒเชพเชเชฌเชพ เชธเชฎเชฏเชฅเซ เชเชธเชชเชพเชธ เชเซ. เชคเซเช 1999เชฎเชพเช เชเชจเซเชเชฐเชจเซเช เชเชเซเชธเชชเซเชฒเซเชฐเชฐเชฎเชพเช, 2004เชฎเชพเช เชซเชพเชฏเชฐเชซเซเชเซเชธเชฎเชพเช เชฆเซเชเชพเชฏเชพ เชนเชคเชพ. เชเซ เชเซ, เชเซเชฌ เชฒเชพเชเชฌเชพ เชธเชฎเชฏเชฅเซ เชเชเซเชธเซเชเซเชเชถเชจ เชฎเชพเชเซ เชเซเช เชเช เชงเซเชฐเชฃ เชจเชนเซเชคเซเช.
เช เชฎเซ เชเชนเซ เชถเชเซเช เชเซ เชคเซ Google Chrome เชจเชพ เชเซเชฅเชพ เชธเชเชธเซเชเชฐเชฃเชฎเชพเช เชเชเซเชธเซเชเซเชเชถเชจ เชธเชพเชฅเซ เชฆเซเชเชพเชฏเซ. เช เชฒเชฌเชคเซเชค, เชคเซเชฏเชพเชฐเซ เชเซเช เชธเซเชชเชทเซเชเซเชเชฐเชฃ เชจเชนเซเชคเซเช, เชชเชฐเชเชคเซ เชคเซ เชเซเชฐเซเชฎ API เชนเชคเซเช เชเซ เชคเซเชจเซ เชเชงเชพเชฐ เชฌเชจเซเชฏเซ: เชฎเซเชเชพเชญเชพเชเชจเชพ เชฌเซเชฐเชพเชเชเชฐ เชฎเชพเชฐเซเชเซเช เชชเชฐ เชตเชฟเชเชฏ เชฎเซเชณเชตเซเชฏเซ เช เชจเซ เชฌเชฟเชฒเซเช-เชเชจ เชเชชเซเชฒเชฟเชเซเชถเชจ เชธเซเชเซเชฐ เชนเซเชตเชพเชจเซ เชเชพเชฐเชฃเซ, เชเซเชฐเซเชฎเซ เชตเชพเชธเซเชคเชตเชฎเชพเช เชฌเซเชฐเชพเชเชเชฐ เชเชเซเชธเซเชเซเชเชถเชจ เชฎเชพเชเซ เชชเซเชฐเชฎเชพเชฃเชญเซเชค เชธเซเช เชเชฐเซเชฏเซเช.
เชฎเซเชเชฟเชฒเชพเชจเซเช เชชเซเชคเชพเชจเซเช เชธเซเชเชพเชจเซเชกเชฐเซเชก เชนเชคเซเช, เชชเชฐเชเชคเซ เชเซเชฐเซเชฎ เชเชเซเชธเชเซเชจเซเชถเชจเชจเซ เชฒเซเชเชชเซเชฐเชฟเชฏเชคเชพ เชเซเชเชจเซ เชเชเชชเชจเซเช เชธเซเชธเชเชเชค API เชฌเชจเชพเชตเชตเชพเชจเซเช เชจเชเซเชเซ เชเชฐเซเชฏเซเช. 2015 เชฎเชพเช, เชฎเซเชเชฟเชฒเชพเชจเซ เชชเชนเซเชฒ เชชเชฐ, เชเซเชฐเซเชธ-เชฌเซเชฐเชพเชเชเชฐ เชเชเซเชธเซเชเซเชเชถเชจ เชตเชฟเชถเชฟเชทเซเชเชคเชพเช เชชเชฐ เชเชพเชฎ เชเชฐเชตเชพ เชฎเชพเชเซ เชตเชฐเซเชฒเซเชก เชตเชพเชเชก เชตเซเชฌ เชเชจเซเชธเซเชฐเซเชเชฟเชฏเชฎ (W3C) เชจเซ เช เชเชฆเชฐ เชเช เชตเชฟเชถเซเชท เชเซเชฅ เชฌเชจเชพเชตเชตเชพเชฎเชพเช เชเชตเซเชฏเซเช เชนเชคเซเช.
Chrome เชฎเชพเชเซ เชนเชพเชฒเชจเชพ API เชเชเซเชธเซเชเซเชเชถเชจเชจเซ เชเชงเชพเชฐ เชคเชฐเซเชเซ เชฒเซเชตเชพเชฎเชพเช เชเชตเซเชฏเชพ เชนเชคเชพ. เชฎเชพเชเชเซเชฐเซเชธเซเชซเซเชเชจเชพ เชธเชฎเชฐเซเชฅเชจ เชธเชพเชฅเซ เชเชพเชฐเซเชฏ เชนเชพเชฅ เชงเชฐเชตเชพเชฎเชพเช เชเชตเซเชฏเซเช เชนเชคเซเช (เชเซเชเชฒเซ เชงเซเชฐเชฃเชจเชพ เชตเชฟเชเชพเชธเชฎเชพเช เชญเชพเช เชฒเซเชตเชพเชจเซ เชเชจเชเชพเชฐ เชเชฐเซเชฏเซ เชนเชคเซ), เช เชจเซ เชชเชฐเชฟเชฃเชพเชฎเซ เชเช เชกเซเชฐเชพเชซเซเช เชฆเซเชเชพเชฏเซ. .
เชเชชเชเชพเชฐเชฟเช เชฐเซเชคเซ, เชธเซเชชเชทเซเชเซเชเชฐเชฃ เชเช, เชซเชพเชฏเชฐเชซเซเชเซเชธ เช เชจเซ เชเชชเซเชฐเชพ เชฆเซเชตเชพเชฐเชพ เชธเชฎเชฐเซเชฅเชฟเชค เชเซ (เชจเซเชเชง เชเชฐเซ เชเซ เชเซเชฐเซเชฎ เช เชธเซเชเชฟเชฎเชพเช เชจเชฅเซ). เชชเชฐเชเชคเซ เชนเชเซเชเชคเชฎเชพเช, เชชเซเชฐเชฎเชพเชฃเชญเซเชค เชฎเซเชเชพเชญเชพเชเซ เชเซเชฐเซเชฎ เชธเชพเชฅเซ เชธเซเชธเชเชเชค เชเซ, เชเชพเชฐเชฃ เชเซ เชคเซ เชตเชพเชธเซเชคเชตเชฎเชพเช เชคเซเชจเชพ เชเชเซเชธเซเชเซเชเชถเชจเชจเชพ เชเชงเชพเชฐเซ เชฒเชเชพเชฏเซเชฒเซเช เชเซ. เชคเชฎเซ WebExtensions API เชตเชฟเชถเซ เชตเชงเซ เชตเชพเชเชเซ เชถเชเซ เชเซ .
เชตเชฟเชธเซเชคเชฐเชฃ เชฎเชพเชณเชเซเช
เชเชเซเชธเซเชเซเชเชถเชจ เชฎเชพเชเซ เชเชฐเซเชฐเซ เชเซ เชคเซ เชเชเชฎเชพเชคเซเชฐ เชซเชพเชเชฒ เชฎเซเชจเชฟเชซเซเชธเซเช เชเซ (manifest.json). เชคเซ เชตเชฟเชธเซเชคเชฐเชฃ เชฎเชพเชเซ "เชชเซเชฐเชตเซเชถ เชฌเชฟเชเชฆเซ" เชชเชฃ เชเซ.
เชฎเซเชจเชฟเชซเซเชธเซเช
เชธเซเชชเชทเซเชเซเชเชฐเชฃ เชฎเซเชเชฌ, เชฎเซเชจเชฟเชซเซเชธเซเช เชซเชพเชเชฒ เชฎเชพเชจเซเชฏ JSON เชซเชพเชเชฒ เชเซ. เชเชฏเชพ เชฌเซเชฐเชพเชเชเชฐเชฎเชพเช เชเซเช เชถเชเชพเชฏ เชเซ เชคเซเชฎเชพเช เชเช เชเซเช เชธเชชเซเชฐเซเชเซเชก เชเซ เชคเซเชจเซ เชฎเชพเชนเชฟเชคเซ เชธเชพเชฅเซ เชฎเซเชจเชฟเชซเซเชธเซเช เชเซเชจเซเช เชธเชเชชเซเชฐเซเชฃ เชตเชฐเซเชฃเชจ .
เชธเซเชชเชทเซเชเซเชเชฐเชฃเชฎเชพเช เชจ เชนเซเชฏ เชคเซเชตเซ เชเซเชจเซ เช เชตเชเชฃเชตเชพเชฎเชพเช เชเชตเซ เชถเชเซ เชเซ (Chrome เช เชจเซ Firefox เชฌเชเชจเซ เชญเซเชฒเซเชจเซ เชเชพเชฃ เชเชฐเซ เชเซ, เชชเชฐเชเชคเซ เชเชเซเชธเซเชเซเชเชถเชจ เชเชพเชฎ เชเชฐเชตเชพเชจเซเช เชเชพเชฒเซ เชฐเชพเชเซ เชเซ).
เช เชจเซ เชนเซเช เชเซเชเชฒเชพเช เชฎเซเชฆเซเชฆเชพเช เชชเชฐ เชงเซเชฏเชพเชจ เชฆเซเชฐเชตเชพ เชฎเชพเชเชเซ เชเซเช.
- เชชเซเชทเซเช เชญเซเชฎเชฟ โ เชเช เชเชฌเซเชเซเชเซเช เชเซเชฎเชพเช เชจเซเชเซเชจเชพ เชเซเชทเซเชคเซเชฐเซ เชถเชพเชฎเซเชฒ เชเซ:
- เชธเซเชเซเชฐเชฟเชชเซเชเซเชธ โ เชธเซเชเซเชฐเชฟเชชเซเชเซเชธเชจเซ เชถเซเชฐเซเชฃเซ เชเซ เชเซ เชชเซเชทเซเช เชญเซเชฎเชฟ เชธเชเชฆเชฐเซเชญเชฎเชพเช เชเชฒเชพเชตเชตเชพเชฎเชพเช เชเชตเชถเซ (เชเชชเชฃเซ เช เชตเชฟเชถเซ เชฅเซเชกเซ เชตเชพเชฐ เชชเชเซ เชตเชพเชค เชเชฐเซเชถเซเช);
- เชชเซเชทเซเช - เชธเซเชเซเชฐเชฟเชชเซเชเซเชธเชจเซ เชฌเชฆเชฒเซ เชเซ เชเซ เชเชพเชฒเซ เชชเซเชทเซเช เชฎเชพเช เชเชฒเชพเชตเชตเชพเชฎเชพเช เชเชตเชถเซ, เชคเชฎเซ เชธเชพเชฎเชเซเชฐเซ เชธเชพเชฅเซ html เชจเซ เชเชฒเซเชฒเซเช เชเชฐเซ เชถเชเซ เชเซ. เช เชเชฟเชธเซเชธเชพเชฎเชพเช, เชธเซเชเซเชฐเชฟเชชเซเช เชซเซเชฒเซเชกเชจเซ เช เชตเชเชฃเชตเชพเชฎเชพเช เชเชตเชถเซ, เช เชจเซ เชธเซเชเซเชฐเชฟเชชเซเชเซเชธเชจเซ เชธเชพเชฎเชเซเชฐเซ เชชเซเชทเซเช เชฎเชพเช เชฆเชพเชเชฒ เชเชฐเชตเชพเชจเซ เชเชฐเซเชฐ เชชเชกเชถเซ;
- เชเชพเชฒเซ โ เชฆเซเชตเชฟเชธเชเชเซ เชงเซเชตเช, เชเซ เชเชฒเซเชฒเซเชเชฟเชค เชจ เชนเซเชฏ, เชคเซ เชฌเซเชฐเชพเชเชเชฐ เชชเซเชทเซเช เชญเซเชฎเชฟ เชชเซเชฐเชเซเชฐเชฟเชฏเชพเชจเซ "เชฎเชพเชฐเซ เชจเชพเชเชถเซ" เชเซเชฏเชพเชฐเซ เชคเซ เชฎเชพเชจเซ เชเซ เชเซ เชคเซ เชเชเช เชเชฐเซ เชฐเชนเซเชฏเซเช เชจเชฅเซ, เช เชจเซ เชเซ เชเชฐเซเชฐเซ เชนเซเชฏ เชคเซ เชคเซเชจเซ เชชเซเชจเชเชชเซเชฐเชพเชฐเชเชญ เชเชฐเชถเซ. เชจเชนเชฟเชเชคเชฐ, เชเซเชฏเชพเชฐเซ เชฌเซเชฐเชพเชเชเชฐ เชฌเชเชง เชนเซเชฏ เชคเซเชฏเชพเชฐเซ เช เชชเซเชทเซเช เชจเซ เช เชจเชฒเซเชก เชเชฐเชตเชพเชฎเชพเช เชเชตเชถเซ. เชซเชพเชฏเชฐเชซเซเชเซเชธเชฎเชพเช เชธเชชเซเชฐเซเชเซเชก เชจเชฅเซ.
- เชธเชพเชฎเชเซเชฐเซ_เชธเซเชเซเชฐเชฟเชชเซเชเซเชธ โ เชเชฌเซเชเซเชเซเชเซเชธเชจเซ เชเชฐเซ เชเซ เชคเชฎเชจเซ เชตเชฟเชตเชฟเชง เชตเซเชฌ เชชเซเชทเซเช เซ เชชเชฐ เชตเชฟเชตเชฟเชง เชธเซเชเซเชฐเชฟเชชเซเชเซ เชฒเซเชก เชเชฐเชตเชพเชจเซ เชฎเชเชเซเชฐเซ เชเชชเซ เชเซ. เชฆเชฐเซเช เชเชฌเซเชเซเชเซเชเชฎเชพเช เชจเซเชเซเชจเชพ เชฎเชนเชคเซเชตเชชเซเชฐเซเชฃ เชเซเชทเซเชคเซเชฐเซ เชถเชพเชฎเซเชฒ เชเซ:
- เชฎเซเชเซ - , เชเซ เชจเชเซเชเซ เชเชฐเซ เชเซ เชเซ เชเซเช เชเซเชเซเชเชธ เชธเชพเชฎเชเซเชฐเซ เชธเซเชเซเชฐเชฟเชชเซเชเชจเซ เชธเชฎเชพเชตเซเชถ เชเชฐเชตเชพเชฎเชพเช เชเชตเชถเซ เชเซ เชจเชนเซเช.
- js โ เชธเซเชเซเชฐเชฟเชชเซเชเซเชธเชจเซ เชธเซเชเชฟ เชเซ เชเซ เช เชฎเซเชเชฎเชพเช เชฒเซเชก เชเชฐเชตเชพเชฎเชพเช เชเชตเชถเซ;
- เชฌเชพเชเชพเชค_เชฎเซเช - เชเซเชทเซเชคเซเชฐเชฎเชพเชเชฅเซ เชฌเชพเชเชพเชค
matchเช เชซเซเชฒเซเชก เชธเชพเชฅเซ เชฎเซเชณ เชเชพเชคเชพ URL.
- เชชเซเชทเซเช _เชเซเชฐเชฟเชฏเชพ - เชตเชพเชธเซเชคเชตเชฎเชพเช เชเช เชเชฌเซเชเซเชเซเช เชเซ เชเซ เชฌเซเชฐเชพเชเชเชฐเชฎเชพเช เชเชกเซเชฐเซเชธ เชฌเชพเชฐเชจเซ เชฌเชพเชเซเชฎเชพเช เชชเซเชฐเชฆเชฐเซเชถเชฟเชค เชฅเชคเชพ เชเชเชเชจ เช
เชจเซ เชคเซเชจเซ เชธเชพเชฅเซ เชเซเชฐเชฟเชฏเชพเชชเซเชฐเชคเชฟเชเซเชฐเชฟเชฏเชพ เชฎเชพเชเซ เชเชตเชพเชฌเชฆเชพเชฐ เชเซ. เชคเซ เชคเชฎเชจเซ เชชเซเชชเช
เชช เชตเชฟเชจเซเชกเซ เชฆเชฐเซเชถเชพเชตเชตเชพ เชฎเชพเชเซ เชชเชฃ เชชเชฐเชตเชพเชจเชเซ เชเชชเซ เชเซ, เชเซ เชคเชฎเชพเชฐเชพ เชชเซเชคเชพเชจเชพ HTML, CSS เช
เชจเซ JS เชจเซ เชเชชเชฏเซเช เชเชฐเซเชจเซ เชตเซเชฏเชพเชเซเชฏเชพเชฏเชฟเชค เชเชฐเชตเชพเชฎเชพเช เชเชตเซ เชเซ.
- เชกเชฟเชซเซเชฒเซเช_เชชเซเชชเช เชช - เชชเซเชชเช เชช เชเชจเซเชเชฐเชซเซเชธ เชธเชพเชฅเซ HTML เชซเชพเชเชฒเชจเซ เชชเชพเชฅ, CSS เช เชจเซ JS เชธเชฎเชพเชตเซ เชถเชเซ เชเซ.
- เชชเชฐเชตเชพเชจเชเซเช - เชเชเซเชธเซเชเซเชเชถเชจ เช เชงเชฟเชเชพเชฐเซเชจเซเช เชธเชเชเชพเชฒเชจ เชเชฐเชตเชพ เชฎเชพเชเซ เชเช เชเชฐเซ. เชคเซเชฏเชพเช 3 เชชเซเชฐเชเชพเชฐเชจเชพ เช เชงเชฟเชเชพเชฐเซ เชเซ, เชเซเชจเซเช เชตเชฟเชเชคเชตเชพเชฐ เชตเชฐเซเชฃเชจ เชเชฐเชตเชพเชฎเชพเช เชเชตเซเชฏเซเช เชเซ
- เชตเซเชฌ_เชเชเซเชธเซเชธเชฟเชฌเชฒ_เชธเชเชธเชพเชงเชจเซ โ เชเชเซเชธเซเชเซเชเชถเชจ เชธเชเชธเชพเชงเชจเซ เชเซ เชเซ เชตเซเชฌ เชชเซเชทเซเช เชตเชฟเชจเชเชคเซ เชเชฐเซ เชถเชเซ เชเซ, เชเชฆเชพเชนเชฐเชฃ เชคเชฐเซเชเซ, เชเชฌเซเช, JS, CSS, HTML เชซเชพเชเชฒเซ.
- เชฌเชพเชนเซเชฏ เชฐเซเชคเซ_เชเชจเซเชเซเชเซเชฌเชฒ โ เช เชนเซเช เชคเชฎเซ เช เชจเซเชฏ เชเชเซเชธเซเชเซเชเชถเชจ เช เชจเซ เชตเซเชฌ เชชเซเชเชจเชพ เชกเซเชฎเซเชจเซเชธ เชเซ เชเซเชฎเชพเชเชฅเซ เชคเชฎเซ เชเชจเซเชเซเช เชเชฐเซ เชถเชเซ เชเซ เชคเซเชจเชพ ID เชจเซ เชธเซเชชเชทเซเชเชชเชฃเซ เชธเซเชชเชทเซเช เชเชฐเซ เชถเชเซ เชเซ. เชกเซเชฎเซเชจ เชฌเซเชเชพ เชธเซเชคเชฐ เช เชฅเชตเชพ เชเชเซเช เชนเซเช เชถเชเซ เชเซ. เชซเชพเชฏเชฐเชซเซเชเซเชธเชฎเชพเช เชเชพเชฎ เชเชฐเชคเซเช เชจเชฅเซ.
เชเชเซเชเซเชเซเชฏเซเชถเชจ เชธเชเชฆเชฐเซเชญ
เชเชเซเชธเซเชเซเชเชถเชจเชฎเชพเช เชคเซเชฐเชฃ เชเซเชก เชเชเซเชเซเชเซเชฏเซเชถเชจ เชธเชเชฆเชฐเซเชญเซ เชเซ, เชเชเชฒเซ เชเซ, เชเชชเซเชฒเชฟเชเซเชถเชจเชฎเชพเช เชฌเซเชฐเชพเชเชเชฐ API เชจเซ เชเชเซเชธเซเชธเชจเชพ เชตเชฟเชตเชฟเชง เชธเซเชคเชฐเซ เชธเชพเชฅเซ เชคเซเชฐเชฃ เชญเชพเชเซเชจเซ เชธเชฎเชพเชตเซเชถ เชฅเชพเชฏ เชเซ.
เชตเชฟเชธเซเชคเชฐเชฃ เชธเชเชฆเชฐเซเชญ
เชฎเซเชเชพเชญเชพเชเชจเชพ API เช เชนเซเช เชเชชเชฒเชฌเซเชง เชเซ. เช เชธเชเชฆเชฐเซเชญเชฎเชพเช เชคเซเช "เชเซเชตเชเชค" เชเซ:
- เชชเซเชทเซเช เชญเซเชฎเชฟ เชชเซเชทเซเช - เชเชเซเชธเซเชเซเชเชถเชจเชจเซ "เชฌเซเชเชเชจเซเชก" เชญเชพเช. เชซเชพเชเชฒ "เชฌเซเชเชเซเชฐเชพเชเชจเซเชก" เชเซเชจเซ เชเชชเชฏเซเช เชเชฐเซเชจเซ เชฎเซเชจเชฟเชซเซเชธเซเชเชฎเชพเช เชเชฒเซเชฒเซเชเชฟเชค เชเซ.
- เชชเซเชชเช
เชช เชชเซเชทเซเช - เชเซเชฏเชพเชฐเซ เชคเชฎเซ เชเชเซเชธเซเชเซเชเชถเชจ เชเชฏเชเชจ เชชเชฐ เชเซเชฒเชฟเช เชเชฐเซ เชเซ เชคเซเชฏเชพเชฐเซ เชเช เชชเซเชชเช
เชช เชชเซเช เชฆเซเชเชพเชฏ เชเซ. เชเชพเชนเซเชฐเชจเชพเชฎเชพเชฎเชพเช
browser_action->default_popup. - เชเชธเซเชเชฎ เชชเซเชทเซเช - เชเชเซเชธเซเชเซเชเชถเชจ เชชเซเชทเซเช , เชฆเซเชถเซเชฏเชจเชพ เช
เชฒเช เชเซเชฌเชฎเชพเช "เชเซเชตเชเชค".
chrome-extension://<id_ัะฐััะธัะตะฝะธั>/customPage.html.
เช เชธเชเชฆเชฐเซเชญ เชฌเซเชฐเชพเชเชเชฐ เชตเชฟเชจเซเชกเซ เช เชจเซ เชเซ เชฌเซเชธเชฅเซ เชธเซเชตเชคเชเชคเซเชฐ เชฐเซเชคเซ เช เชธเซเชคเชฟเชคเซเชตเชฎเชพเช เชเซ. เชชเซเชทเซเช เชญเซเชฎเชฟ เชชเซเชทเซเช เชเช เชจเชเชฒเชฎเชพเช เช เชธเซเชคเชฟเชคเซเชตเชฎเชพเช เชเซ เช เชจเซ เชนเชเชฎเซเชถเชพ เชเชพเชฐเซเชฏ เชเชฐเซ เชเซ (เช เชชเชตเชพเชฆ เช เชเชตเซเชจเซเช เชชเซเชทเซเช เชเซ, เชเซเชฏเชพเชฐเซ เชชเซเชทเซเช เชญเซเชฎเชฟ เชธเซเชเซเชฐเชฟเชชเซเช เชเชตเซเชจเซเช เชฆเซเชตเชพเชฐเชพ เชฒเซเชจเซเช เชเชฐเชตเชพเชฎเชพเช เชเชตเซ เชเซ เช เชจเซ เชคเซเชจเชพ เช เชฎเชฒ เชชเชเซ "เชฎเซเชคเซเชฏเซ เชชเชพเชฎเซ เชเซ). เชชเซเชชเช เชช เชชเซเชทเซเช เชเซเชฏเชพเชฐเซ เชชเซเชชเช เชช เชตเชฟเชจเซเชกเซ เชเซเชฒเซเชฒเซ เชนเซเชฏ เชคเซเชฏเชพเชฐเซ เช เชธเซเชคเชฟเชคเซเชตเชฎเชพเช เชเซ, เช เชจเซ เชเชธเซเชเชฎ เชชเซเชทเซเช โ เชเซเชฏเชพเชฐเซ เชคเซเชจเซ เชธเชพเชฅเซเชจเซ เชเซเชฌ เชเซเชฒเซเชฒเซ เชนเซเชฏ. เช เชธเชเชฆเชฐเซเชญเชฎเชพเชเชฅเซ เช เชจเซเชฏ เชเซเชฌเซเชธ เช เชจเซ เชคเซเชฎเชจเชพ เชธเชฎเชพเชตเชฟเชทเซเชเซเชจเซ เชเซเช เชเชเซเชธเซเชธ เชจเชฅเซ.
เชธเชพเชฎเชเซเชฐเซ เชธเซเชเซเชฐเชฟเชชเซเช เชธเชเชฆเชฐเซเชญ
เชธเชพเชฎเชเซเชฐเซ เชธเซเชเซเชฐเชฟเชชเซเช เชซเชพเชเชฒ เชฆเชฐเซเช เชฌเซเชฐเชพเชเชเชฐ เชเซเชฌ เชธเชพเชฅเซ เชฒเซเชจเซเช เชเชฐเชตเชพเชฎเชพเช เชเชตเซ เชเซ. เชคเซเชจเซ เชชเชพเชธเซ เชเชเซเชธเซเชเซเชเชถเชจเชจเชพ API เชจเชพ เชญเชพเช เช
เชจเซ เชตเซเชฌ เชชเซเชทเซเช เชจเชพ DOM เชเซเชฐเซเชจเซ เชเชเซเชธเซเชธ เชเซ. เชคเซ เชธเชพเชฎเชเซเชฐเซ เชธเซเชเซเชฐเชฟเชชเซเชเซ เชเซ เชเซ เชชเซเชทเซเช เชธเชพเชฅเซ เชเซเชฐเชฟเชฏเชพเชชเซเชฐเชคเชฟเชเซเชฐเชฟเชฏเชพ เชฎเชพเชเซ เชเชตเชพเชฌเชฆเชพเชฐ เชเซ. เชเชเซเชธเซเชเซเชเชถเชจเซเชธ เชเซ เชเซ DOM เชเซเชฐเซเชจเซ เชฎเซเชจเชฟเชชเซเชฏเซเชฒเซเช เชเชฐเซ เชเซ เชคเซ เชธเชพเชฎเชเซเชฐเซ เชธเซเชเซเชฐเชฟเชชเซเชเซเชธเชฎเชพเช เช เชเชฐเซ เชเซ - เชเชฆเชพเชนเชฐเชฃ เชคเชฐเซเชเซ, เชเชก เชฌเซเชฒเซเชเชฐเซเชธ เช
เชฅเชตเชพ เช
เชจเซเชตเชพเชฆเชเซ. เชเชชเชฐเชพเชเชค, เชธเชพเชฎเชเซเชฐเซ เชธเซเชเซเชฐเชฟเชชเซเช เชชเซเชฐเชฎเชพเชฃเชญเซเชค เชฆเซเชตเชพเชฐเชพ เชชเซเชทเซเช เชธเชพเชฅเซ เชตเชพเชคเชเซเชค เชเชฐเซ เชถเชเซ เชเซ postMessage.
เชตเซเชฌ เชชเซเชทเซเช เชธเชเชฆเชฐเซเชญ
เช เชชเซเชคเซ เช เชตเชพเชธเซเชคเชตเชฟเช เชตเซเชฌ เชชเซเช เชเซ. เชคเซเชจเซ เชเชเซเชธเซเชเซเชเชถเชจ เชธเชพเชฅเซ เชเซเช เชฒเซเชตเชพเชฆเซเชตเชพ เชจเชฅเซ เช เชจเซ เชคเซเชจเซ เชชเชพเชธเซ เชคเซเชฏเชพเช เชเชเซเชธเซเชธ เชจเชฅเซ, เชธเชฟเชตเชพเชฏ เชเซ เช เชชเซเชทเซเช เชจเซเช เชกเซเชฎเซเชจ เชฎเซเชจเชฟเชซเซเชธเซเชเชฎเชพเช เชธเซเชชเชทเซเชเชชเชฃเซ เชฆเชฐเซเชถเชพเชตเชตเชพเชฎเชพเช เชเชตเซเชฏเซเช เชจเชฅเซ (เชจเซเชเซ เชเชจเชพ เชชเชฐ เชตเชงเซ).
เชธเชเชฆเซเชถ เชตเชฟเชจเชฟเชฎเชฏ
เชเชชเซเชฒเชฟเชเซเชถเชจเชจเชพ เชตเชฟเชตเชฟเชง เชญเชพเชเซเช เชเชเชฌเซเชเชพ เชธเชพเชฅเซ เชธเชเชฆเซเชถเชพเชเชจเซ เชเชชเชฒเซ เชเชฐเชตเซ เชเชตเชถเซเชฏเช เชเซ. เช เชฎเชพเชเซ เชเช API เชเซ runtime.sendMessage เชธเชเชฆเซเชถ เชฎเซเชเชฒเชตเชพ เชฎเชพเชเซ background ะธ tabs.sendMessage เชชเซเชทเซเช เชชเชฐ เชธเชเชฆเซเชถ เชฎเซเชเชฒเชตเชพ เชฎเชพเชเซ (เชธเชพเชฎเชเซเชฐเซ เชธเซเชเซเชฐเชฟเชชเซเช, เชชเซเชชเช
เชช เช
เชฅเชตเชพ เชตเซเชฌ เชชเซเชทเซเช เชเซ เชเชชเชฒเชฌเซเชง เชนเซเชฏ เชคเซ externally_connectable). Chrome API เชจเซ เชเชเซเชธเซเชธ เชเชฐเชคเซ เชตเชเชคเซ เชจเซเชเซ เชเช เชเชฆเชพเชนเชฐเชฃ เชเซ.
// ะกะพะพะฑัะตะฝะธะตะผ ะผะพะถะตั ะฑััั ะปัะฑะพะน JSON ัะตัะธะฐะปะธะทัะตะผัะน ะพะฑัะตะบั
const msg = {a: 'foo', b: 'bar'};
// extensionId ะผะพะถะฝะพ ะฝะต ัะบะฐะทัะฒะฐัั, ะตัะปะธ ะผั ั
ะพัะธะผ ะฟะพัะปะฐัั ัะพะพะฑัะตะฝะธะต 'ัะฒะพะตะผั' ัะฐััะธัะตะฝะธั (ะธะท ui ะธะปะธ ะบะพะฝัะตะฝั ัะบัะธะฟัะฐ)
chrome.runtime.sendMessage(extensionId, msg);
// ะขะฐะบ ะฒัะณะปัะดะธั ะพะฑัะฐะฑะพััะธะบ
chrome.runtime.onMessage.addListener((msg) => console.log(msg))
// ะะพะถะฝะพ ัะปะฐัั ัะพะพะฑัะตะฝะธั ะฒะบะปะฐะดะบะฐะผ ะทะฝะฐั ะธั
id
chrome.tabs.sendMessage(tabId, msg)
// ะะพะปััะธัั ะบ ะฒะบะปะฐะดะบะฐะผ ะธ ะธั
id ะผะพะถะฝะพ, ะฝะฐะฟัะธะผะตั, ะฒะพั ัะฐะบ
chrome.tabs.query(
{currentWindow: true, active : true},
function(tabArray){
tabArray.forEach(tab => console.log(tab.id))
}
)เชธเชเชชเซเชฐเซเชฃ เชธเชเชเชพเชฐ เชฎเชพเชเซ, เชคเชฎเซ เชฎเชพเชฐเชซเชคเซ เชเซเชกเชพเชฃเซ เชฌเชจเชพเชตเซ เชถเชเซ เชเซ runtime.connect. เชเชตเชพเชฌเชฎเชพเช เช
เชฎเซ เชชเซเชฐเชพเชชเซเชค เชเชฐเซเชถเซเช runtime.Port, เชเซเชจเชพ เชชเชฐ, เชเซเชฏเชพเชฐเซ เชคเซ เชเซเชฒเซเชฒเซเช เชนเซเชฏ, เชคเซเชฏเชพเชฐเซ เชคเชฎเซ เชเชฎเซ เชคเซเชเชฒเชพ เชธเชเชฆเซเชถเชพเช เชฎเซเชเชฒเซ เชถเชเซ เชเซ. เชเซเชฒเชพเชฏเชเช เชฌเชพเชเซ เชชเชฐ, เชเชฆเชพเชนเชฐเชฃ เชคเชฐเซเชเซ, contentscript, เชคเซ เชเชจเชพ เชเซเชตเซเช เชฆเซเชเชพเชฏ เชเซ:
// ะะฟััั ะถะต extensionId ะผะพะถะฝะพ ะฝะต ัะบะฐะทัะฒะฐัั ะฟัะธ ะบะพะผะผัะฝะธะบะฐัะธะธ ะฒะฝัััะธ ะพะดะฝะพะณะพ ัะฐััะธัะตะฝะธั. ะะพะดะบะปััะตะฝะธะต ะผะพะถะฝะพ ะธะผะตะฝะพะฒะฐัั
const port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
if (msg.question === "Who's there?")
port.postMessage({answer: "Madame"});
else if (msg.question === "Madame who?")
port.postMessage({answer: "Madame... Bovary"});
เชธเชฐเซเชตเชฐ เช เชฅเชตเชพ เชชเซเชทเซเช เชญเซเชฎเชฟ:
// ะะฑัะฐะฑะพััะธะบ ะดะปั ะฟะพะดะบะปััะตะฝะธั 'ัะฒะพะธั
' ะฒะบะปะฐะดะพะบ. ะะพะฝัะตะฝั ัะบัะธะฟัะพะฒ, popup ะธะปะธ ัััะฐะฝะธั ัะฐััะธัะตะฝะธั
chrome.runtime.onConnect.addListener(function(port) {
console.assert(port.name === "knockknock");
port.onMessage.addListener(function(msg) {
if (msg.joke === "Knock knock")
port.postMessage({question: "Who's there?"});
else if (msg.answer === "Madame")
port.postMessage({question: "Madame who?"});
else if (msg.answer === "Madame... Bovary")
port.postMessage({question: "I don't get it."});
});
});
// ะะฑัะฐะฑะพััะธะบ ะดะปั ะฟะพะดะบะปััะตะฝะธั ะฒะฝะตัะฝะธั
ะฒะบะปะฐะดะพะบ. ะััะณะธั
ัะฐััะธัะตะฝะธะน ะธะปะธ ะฒะตะฑ ัััะฐะฝะธั, ะบะพัะพััะผ ัะฐะทัะตัะตะฝ ะดะพัััะฟ ะฒ ะผะฐะฝะธัะตััะต
chrome.runtime.onConnectExternal.addListener(function(port) {
...
});เชเช เชชเซเชฐเชธเชเช เชชเชฃ เชเซ onDisconnect เช
เชจเซ เชชเชฆเซเชงเชคเชฟ disconnect.
เชเชชเซเชฒเชฟเชเซเชถเชจ เชกเชพเชฏเชพเชเซเชฐเชพเชฎ
เชเชพเชฒเซ เชเช เชฌเซเชฐเชพเชเชเชฐ เชเชเซเชธเซเชเซเชเชถเชจ เชฌเชจเชพเชตเซเช เชเซ เชเชพเชจเชเซ เชเซเชจเซ เชธเชเชเซเชฐเชนเชฟเชค เชเชฐเซ เชเซ, เชธเชพเชฐเซเชตเชเชจเชฟเช เชฎเชพเชนเชฟเชคเซเชจเซ เชเชเซเชธเซเชธ เชชเซเชฐเชฆเชพเชจ เชเชฐเซ เชเซ (เชธเชฐเชจเชพเชฎเซเช, เชธเชพเชฐเซเชตเชเชจเชฟเช เชเซ เชชเซเชทเซเช เชธเชพเชฅเซ เชตเชพเชคเชเซเชค เชเชฐเซ เชเซ เช เชจเซ เชคเซเชคเซเชฏ-เชชเชเซเชท เชเชชเซเชฒเชฟเชเซเชถเชจเซเชจเซ เชตเซเชฏเชตเชนเชพเชฐเซ เชฎเชพเชเซ เชธเชนเซ เชฎเชพเชเซ เชตเชฟเชจเชเชคเซ เชเชฐเชตเชพเชจเซ เชฎเชเชเซเชฐเซ เชเชชเซ เชเซ.
เชเชชเซเชฒเชฟเชเซเชถเชจ เชตเชฟเชเชพเชธ
เช
เชฎเชพเชฐเซ เชเชชเซเชฒเชฟเชเซเชถเชจ เชฌเชเชจเซเช เชตเชชเชฐเชพเชถเชเชฐเซเชคเชพ เชธเชพเชฅเซ เชเซเชฐเชฟเชฏเชพเชชเซเชฐเชคเชฟเชเซเชฐเชฟเชฏเชพ เชเชฐเชตเซ เชเซเชเช เช
เชจเซ เชเซเชฒ เชชเชฆเซเชงเชคเชฟเช (เชเชฆเชพเชนเชฐเชฃ เชคเชฐเซเชเซ, เชตเซเชฏเชตเชนเชพเชฐเซ เชชเชฐ เชนเชธเซเชคเชพเชเซเชทเชฐ เชเชฐเชตเชพ เชฎเชพเชเซ) เชฎเชพเชเซ API เชธเชพเชฅเซ เชชเซเชทเซเช เชชเซเชฐเชฆเชพเชจ เชเชฐเชตเซเช เชเซเชเช. เชฎเชพเชคเซเชฐ เชเช เชธเชพเชฅเซ เชเชฐเซ contentscript เชเชพเชฎ เชเชฐเชถเซ เชจเชนเซเช, เชเชพเชฐเชฃ เชเซ เชคเซเชจเซ เชชเชพเชธเซ เชซเชเซเชค DOM เชจเซ เช เชเชเซเชธเซเชธ เชเซ, เชชเชฐเชเชคเซ เชชเซเชเชจเชพ JS เชฎเชพเชเซ เชจเชนเซเช. เชฆเซเชตเชพเชฐเชพ เชเชจเซเชเซเช เชเชฐเซ runtime.connect เช
เชฎเซ เชเชฐเซ เชถเชเชคเชพ เชจเชฅเซ, เชเชพเชฐเชฃ เชเซ API เชฌเชงเชพ เชกเซเชฎเซเชจเซเชธ เชชเชฐ เชเชฐเซเชฐเซ เชเซ เช
เชจเซ เชฎเซเชจเชฟเชซเซเชธเซเชเชฎเชพเช เชฎเชพเชคเซเชฐ เชเซเชเซเชเชธ เช เชเชฒเซเชฒเซเชเชฟเชค เชเชฐเซ เชถเชเชพเชฏ เชเซ. เชชเชฐเชฟเชฃเชพเชฎเซ, เชกเชพเชฏเชพเชเซเชฐเชพเชฎ เชเชจเชพ เชเซเชตเซ เชฆเซเชเชพเชถเซ:

เชฌเซเชเซ เชธเซเชเซเชฐเชฟเชชเซเช เชนเชถเซ - inpage, เชเซ เช
เชฎเซ เชชเซเชทเซเช เชฎเชพเช เชฆเชพเชเชฒ เชเชฐเซเชถเซเช. เชคเซ เชคเซเชจเชพ เชธเชเชฆเชฐเซเชญเชฎเชพเช เชเชพเชฒเชถเซ เช
เชจเซ เชเชเซเชธเซเชเซเชเชถเชจ เชธเชพเชฅเซ เชเชพเชฎ เชเชฐเชตเชพ เชฎเชพเชเซ API เชชเซเชฐเชฆเชพเชจ เชเชฐเชถเซ.
เชถเชฐเซเชเชค
เชฌเชงเชพ เชฌเซเชฐเชพเชเชเชฐ เชเชเซเชธเซเชเซเชเชถเชจ เชเซเชก เชชเชฐ เชเชชเชฒเชฌเซเชง เชเซ . เชตเชฐเซเชฃเชจ เชฆเชฐเชฎเชฟเชฏเชพเชจ เชเชฎเชฟเชเซเชธเชจเซ เชฒเชฟเชเชเซเชธ เชนเชถเซ.
เชเชพเชฒเซ เชฎเซเชจเชฟเชซเซเชธเซเชเซ เชธเชพเชฅเซ เชชเซเชฐเชพเชฐเชเชญ เชเชฐเซเช:
{
// ะะผั ะธ ะพะฟะธัะฐะฝะธะต, ะฒะตััะธั. ะัะต ััะพ ะฑัะดะตั ะฒะธะดะฝะพ ะฒ ะฑัะฐัะทะตัะต ะฒ chrome://extensions/?id=<id ัะฐััะธัะตะฝะธั>
"name": "Signer",
"description": "Extension demo",
"version": "0.0.1",
"manifest_version": 2,
// ะกะบัะธะฟัั, ะบะพัะพััะต ะฑัะดัั ะธัะฟะพะปะฝัััั ะฒ background, ะธั
ะผะพะถะตั ะฑััั ะฝะตัะบะพะปัะบะพ
"background": {
"scripts": ["background.js"]
},
// ะะฐะบะพะน html ะธัะฟะพะปัะทะพะฒะฐัั ะดะปั popup
"browser_action": {
"default_title": "My Extension",
"default_popup": "popup.html"
},
// ะะพะฝัะตะฝั ัะบัะธะฟัั.
// ะฃ ะฝะฐั ะพะดะธะฝ ะพะฑัะตะบั: ะดะปั ะฒัะตั
url ะฝะฐัะธะฝะฐััะธั
ัั ั http ะธะปะธ https ะผั ะทะฐะฟััะบะฐะตะผ
// contenscript context ัะพ ัะบัะธะฟัะพะผ contentscript.js. ะะฐะฟััะบะฐัั ััะฐะทั ะฟะพ ะฟะพะปััะตะฝะธะธ ะดะพะบัะผะตะฝัะฐ ะดะปั ะฒัะตั
ััะตะนะผะพะฒ
"content_scripts": [
{
"matches": [
"http://*/*",
"https://*/*"
],
"js": [
"contentscript.js"
],
"run_at": "document_start",
"all_frames": true
}
],
// ะ ะฐะทัะตัะตะฝ ะดะพัััะฟ ะบ localStorage ะธ idle api
"permissions": [
"storage",
// "unlimitedStorage",
//"clipboardWrite",
"idle"
//"activeTab",
//"webRequest",
//"notifications",
//"tabs"
],
// ะะดะตัั ัะบะฐะทัะฒะฐัััั ัะตััััั, ะบ ะบะพัะพััะผ ะฑัะดะตั ะธะผะตัั ะดะพัััะฟ ะฒะตะฑ ัััะฐะฝะธัะฐ. ะขะพะตััั ะธั
ะผะพะถะฝะพ ะฑัะดะตั ะทะฐะฟัะฐัะธะฒะฐัั fetche'ะผ ะธะปะธ ะฟัะพััะพ xhr
"web_accessible_resources": ["inpage.js"]
}เชเชพเชฒเซ background.js, popup.js, inpage.js เช เชจเซ contentscript.js เชฌเชจเชพเชตเซ. เช เชฎเซ popup.html เชเชฎเซเชฐเซเช เชเซเช - เช เชจเซ เช เชฎเชพเชฐเซ เชเชชเซเชฒเชฟเชเซเชถเชจ เชชเชนเซเชฒเซเชฅเซ เช Google Chrome เชฎเชพเช เชฒเซเชก เชฅเช เชถเชเซ เชเซ เช เชจเซ เชเชพเชคเชฐเซ เชเชฐเซ เชเซ เชคเซ เชเชพเชฐเซเชฏ เชเชฐเซ เชเซ.
เชเชจเซ เชเชเชพเชธเชตเชพ เชฎเชพเชเซ, เชคเชฎเซ เชเซเชก เชฒเช เชถเชเซ เชเซ . เช เชฎเซ เชเซ เชเชฐเซเชฏเซเช เชคเซ เชเชชเชฐเชพเชเชค, เชฒเชฟเชเช เชตเซเชฌเชชเซเชเชจเซ เชเชชเชฏเซเช เชเชฐเซเชจเซ เชชเซเชฐเซเชเซเชเซเชเชจเซ เชเชธเซเชฎเซเชฌเชฒเซเชจเซ เชเซเช เชตเซ เชเซ. เชฌเซเชฐเชพเชเชเชฐเชฎเชพเช เชเชชเซเชฒเชฟเชเซเชถเชจ เชเชฎเซเชฐเชตเชพ เชฎเชพเชเซ, chrome://extensions เชฎเชพเช เชคเชฎเชพเชฐเซ เชฒเซเชก เช เชจเชชเซเชเซเชก เช เชจเซ เช เชจเซเชฐเซเชช เชเชเซเชธเซเชเซเชเชถเชจ เชธเชพเชฅเซ เชซเซเชฒเซเชกเชฐ เชชเชธเชเชฆ เชเชฐเชตเชพเชจเซ เชเชฐเซเชฐ เชเซ - เช เชฎเชพเชฐเชพ เชเชฟเชธเซเชธเชพเชฎเชพเช เชเซ.

เชนเชตเซ เช เชฎเชพเชฐเซเช เชเชเซเชธเซเชเซเชเชถเชจ เชเชจเซเชธเซเชเซเชฒ เชฅเช เชเชฏเซเช เชเซ เช เชจเซ เชเชพเชฎ เชเชฐเซ เชฐเชนเซเชฏเซเช เชเซ. เชคเชฎเซ เชจเซเชเซ เชชเซเชฐเชฎเชพเชฃเซ เชตเชฟเชตเชฟเชง เชธเชเชฆเชฐเซเชญเซ เชฎเชพเชเซ เชตเชฟเชเชพเชธเชเชฐเซเชคเชพ เชธเชพเชงเชจเซ เชเชฒเชพเชตเซ เชถเชเซ เชเซ:
เชชเซเชชเช เชช ->

เชธเชพเชฎเชเซเชฐเซ เชธเซเชเซเชฐเชฟเชชเซเช เชเชจเซเชธเซเชฒเชจเซ เชเชเซเชธเซเชธ เชคเซ เชชเซเชทเซเช เชจเชพ เช เชเชจเซเชธเซเชฒ เชฆเซเชตเชพเชฐเชพ เชนเชพเชฅ เชงเชฐเชตเชพเชฎเชพเช เชเชตเซ เชเซ เชเซเชจเชพ เชชเชฐ เชคเซ เชฒเซเชจเซเช เชเชฐเชตเชพเชฎเชพเช เชเชตเซเชฏเซเช เชเซ.
เชธเชเชฆเซเชถ เชตเชฟเชจเชฟเชฎเชฏ
เชคเซเชฅเซ, เชเชชเชฃเซ เชฌเซ เชธเชเชเชพเชฐ เชเซเชจเชฒเซ เชธเซเชฅเชพเชชเชฟเชค เชเชฐเชตเชพเชจเซ เชเชฐเซเชฐ เชเซ: inpage <-> เชชเซเชทเซเช เชญเซเชฎเชฟ เช เชจเซ เชชเซเชชเช เชช <-> เชชเซเชทเซเช เชญเซเชฎเชฟ. เชคเชฎเซ, เช เชฒเชฌเชคเซเชค, เชซเชเซเชค เชชเซเชฐเซเช เชชเชฐ เชธเชเชฆเซเชถเชพ เชฎเซเชเชฒเซ เชถเชเซ เชเซ เช เชจเซ เชคเชฎเชพเชฐเชพ เชชเซเชคเชพเชจเชพ เชชเซเชฐเซเชเซเชเซเชฒเชจเซ เชถเซเชง เชเชฐเซ เชถเชเซ เชเซ, เชชเชฐเชเชคเซ เชนเซเช เชฎเซเชเชพเชฎเชพเชธเซเช เชเชชเชจ เชธเซเชฐเซเชธ เชชเซเชฐเซเชเซเชเซเชเชฎเชพเช เชเซเชฏเซเชฒเชพ เช เชญเชฟเชเชฎเชจเซ เชชเชธเชเชฆ เชเชฐเซเช เชเซเช.
เช Ethereum เชจเซเชเชตเชฐเซเช เชธเชพเชฅเซ เชเชพเชฎ เชเชฐเชตเชพ เชฎเชพเชเซ เชเช เชฌเซเชฐเชพเชเชเชฐ เชเชเซเชธเซเชเซเชเชถเชจ เชเซ. เชคเซเชฎเชพเช, เชเชชเซเชฒเชฟเชเซเชถเชจเชจเชพ เชตเชฟเชตเชฟเชง เชญเชพเชเซ dnode เชฒเชพเชเชฌเซเชฐเซเชฐเซเชจเซ เชเชชเชฏเซเช เชเชฐเซเชจเซ RPC เชฆเซเชตเชพเชฐเชพ เชตเชพเชคเชเซเชค เชเชฐเซ เชเซ. เชเซ เชคเชฎเซ เชคเซเชจเซ เชชเชฐเชฟเชตเชนเชจ เชคเชฐเซเชเซ เชจเซเชกเช เชธเซเชเซเชฐเซเชฎ เชธเชพเชฅเซ เชชเซเชฐเชฆเชพเชจ เชเชฐเซ เชเซ เชคเซ เชคเซ เชคเชฎเชจเซ เชเซเชฌ เช เชเชกเชชเชฅเซ เช เชจเซ เชธเชเชตเชกเชคเชพเชชเซเชฐเซเชตเช เชเชเซเชธเชเซเชจเซเชเชจเซเช เชเชฏเซเชเชจ เชเชฐเชตเชพเชจเซ เชฎเชเชเซเชฐเซ เชเชชเซ เชเซ (เชเชเชฒเซ โโเชเซ เชเชฌเซเชเซเชเซเช เชเซ เชธเชฎเชพเชจ เชเชจเซเชเชฐเชซเซเชธเชจเซ เชฒเชพเชเซ เชเชฐเซ เชเซ):
import Dnode from "dnode/browser";
// ะ ััะพะผ ะฟัะธะผะตัะต ััะปะพะฒะธะผัั ััะพ ะบะปะธะตะฝั ัะดะฐะปะตะฝะฝะพ ะฒัะทัะฒะฐะตั ััะฝะบัะธะธ ะฝะฐ ัะตัะฒะตัะต, ั
ะพัั ะฝะธัะตะณะพ ะฝะฐะผ ะฝะต ะผะตัะฐะตั ัะดะตะปะฐัั ััะพ ะดะฒัะฝะฐะฟัะฐะฒะปะตะฝะฝัะผ
// Cะตัะฒะตั
// API, ะบะพัะพัะพะต ะผั ั
ะพัะธะผ ะฟัะตะดะพััะฐะฒะธัั
const dnode = Dnode({
hello: (cb) => cb(null, "world")
})
// ะขัะฐะฝัะฟะพัั, ะฟะพะฒะตัั
ะบะพัะพัะพะณะพ ะฑัะดะตั ัะฐะฑะพัะฐัั dnode. ะัะฑะพะน nodejs ัััะธะผ. ะ ะฑัะฐัะทะตัะต ะตััั ะฑะธะฑะธะปะธะพัะตะบะฐ 'readable-stream'
connectionStream.pipe(dnode).pipe(connectionStream)
// ะะปะธะตะฝั
const dnodeClient = Dnode() // ะัะทะพะฒ ะฑะตะท ะฐะณััะผะตะฝัะฐ ะทะฝะฐัะธั ััะพ ะผั ะฝะต ะฟัะตะดะพััะฐะฒะปัะตะผ API ะฝะฐ ะดััะณะพะน ััะพัะพะฝะต
// ะัะฒะตะดะตั ะฒ ะบะพะฝัะพะปั world
dnodeClient.once('remote', remote => {
remote.hello(((err, value) => console.log(value)))
})เชนเชตเซ เชเชชเชฃเซ เชเชชเซเชฒเชฟเชเซเชถเชจ เชเซเชฒเชพเชธ เชฌเชจเชพเชตเซเชถเซเช. เชคเซ เชชเซเชชเช เชช เช เชจเซ เชตเซเชฌ เชชเซเช เชฎเชพเชเซ API เชเชฌเซเชเซเชเซเช เชฌเชจเชพเชตเชถเซ เช เชจเซ เชคเซเชฎเชจเชพ เชฎเชพเชเซ เชกเซเชจเซเชก เชฌเชจเชพเชตเชถเซ:
import Dnode from 'dnode/browser';
export class SignerApp {
// ะะพะทะฒัะฐัะฐะตั ะพะฑัะตะบั API ะดะปั ui
popupApi(){
return {
hello: cb => cb(null, 'world')
}
}
// ะะพะทะฒัะฐัะฐะตั ะพะฑัะตั API ะดะปั ัััะฐะฝะธัั
pageApi(){
return {
hello: cb => cb(null, 'world')
}
}
// ะะพะดะบะปััะฐะตั popup ui
connectPopup(connectionStream){
const api = this.popupApi();
const dnode = Dnode(api);
connectionStream.pipe(dnode).pipe(connectionStream);
dnode.on('remote', (remote) => {
console.log(remote)
})
}
// ะะพะดะบะปััะฐะตั ัััะฐะฝะธัั
connectPage(connectionStream, origin){
const api = this.popupApi();
const dnode = Dnode(api);
connectionStream.pipe(dnode).pipe(connectionStream);
dnode.on('remote', (remote) => {
console.log(origin);
console.log(remote)
})
}
}เช เชนเซเช เช เชจเซ เชจเซเชเซ, เชตเซเชถเซเชตเชฟเช เชเซเชฐเซเชฎ เชเชฌเซเชเซเชเซเชเชจเซ เชฌเชฆเชฒเซ, เช เชฎเซ เชเชเซเชธเชเซเชจเซเชถเชจ เชเชชเซเชเชเชจเซ เชเชชเชฏเซเช เชเชฐเซเช เชเซเช, เชเซ Google เชจเชพ เชฌเซเชฐเชพเชเชเชฐเชฎเชพเช เชเซเชฐเซเชฎ เช เชจเซ เช เชจเซเชฏเชฎเชพเช เชฌเซเชฐเชพเชเชเชฐเชจเซ เชเชเซเชธเซเชธ เชเชฐเซ เชเซ. เช เชเซเชฐเซเชธ-เชฌเซเชฐเชพเชเชเชฐ เชธเซเชธเชเชเชคเชคเชพ เชฎเชพเชเซ เชเชฐเชตเชพเชฎเชพเช เชเชตเซ เชเซ, เชชเชฐเชเชคเซ เช เชฒเซเชเชจเชพ เชนเซเชคเซเช เชฎเชพเชเซ เชเซเช เชซเชเซเชค 'chrome.runtime.connect' เชจเซ เชเชชเชฏเซเช เชเชฐเซ เชถเชเซ เชเซ.
เชเชพเชฒเซ เชชเซเชทเซเช เชญเซเชฎเชฟ เชธเซเชเซเชฐเชฟเชชเซเชเชฎเชพเช เชเชชเซเชฒเชฟเชเซเชถเชจ เชฆเชพเชเชฒเซ เชฌเชจเชพเชตเซเช:
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";
const app = new SignerApp();
// onConnect ััะฐะฑะฐััะฒะฐะตั ะฟัะธ ะฟะพะดะบะปััะตะฝะธะธ 'ะฟัะพัะตััะพะฒ' (contentscript, popup, ะธะปะธ ัััะฐะฝะธัะฐ ัะฐััะธัะตะฝะธั)
extensionApi.runtime.onConnect.addListener(connectRemote);
function connectRemote(remotePort) {
const processName = remotePort.name;
const portStream = new PortStream(remotePort);
// ะัะธ ัััะฐะฝะพะฒะบะต ัะพะตะดะธะฝะตะฝะธั ะผะพะถะฝะพ ัะบะฐะทัะฒะฐัั ะธะผั, ะฟะพ ััะพะผั ะธะผะตะฝะธ ะผั ะธ ะพะฟะฟัะตะดะตะปัะตะผ ะบัะพ ะบ ะฝะฐะผ ะฟะพะดะปััะธะปัั, ะบะพะฝัะตะฝััะบัะธะฟั ะธะปะธ ui
if (processName === 'contentscript'){
const origin = remotePort.sender.url
app.connectPage(portStream, origin)
}else{
app.connectPopup(portStream)
}
}เชเชพเชฐเชฃ เชเซ dnode เชธเซเชเซเชฐเซเชฎเซเชธ เชธเชพเชฅเซ เชเชพเชฎ เชเชฐเซ เชเซ, เช เชจเซ เช เชฎเชจเซ เชชเซเชฐเซเช เชชเซเชฐเชพเชชเซเชค เชฅเชพเชฏ เชเซ, เชเชกเซเชชเซเชเชฐ เชตเชฐเซเชเชจเซ เชเชฐเซเชฐ เชเซ. เชคเซ เชตเชพเชเชเซ เชถเชเชพเชฏ เชคเซเชตเซ-เชธเซเชเซเชฐเซเชฎ เชฒเชพเชเชฌเซเชฐเซเชฐเซเชจเซ เชเชชเชฏเซเช เชเชฐเซเชจเซ เชฌเชจเชพเชตเชตเชพเชฎเชพเช เชเชตเซ เชเซ, เชเซ เชฌเซเชฐเชพเชเชเชฐเชฎเชพเช เชจเซเชกเช เชธเซเชเซเชฐเซเชฎเซเชธ เชฒเชพเชเซ เชเชฐเซ เชเซ:
import {Duplex} from 'readable-stream';
export class PortStream extends Duplex{
constructor(port){
super({objectMode: true});
this._port = port;
port.onMessage.addListener(this._onMessage.bind(this));
port.onDisconnect.addListener(this._onDisconnect.bind(this))
}
_onMessage(msg) {
if (Buffer.isBuffer(msg)) {
delete msg._isBuffer;
const data = new Buffer(msg);
this.push(data)
} else {
this.push(msg)
}
}
_onDisconnect() {
this.destroy()
}
_read(){}
_write(msg, encoding, cb) {
try {
if (Buffer.isBuffer(msg)) {
const data = msg.toJSON();
data._isBuffer = true;
this._port.postMessage(data)
} else {
this._port.postMessage(msg)
}
} catch (err) {
return cb(new Error('PortStream - disconnected'))
}
cb()
}
}เชนเชตเซ เชเชพเชฒเซ UI เชฎเชพเช เชเชจเซเชเซเชถเชจ เชฌเชจเชพเชตเซเช:
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import Dnode from 'dnode/browser';
const DEV_MODE = process.env.NODE_ENV !== 'production';
setupUi().catch(console.error);
async function setupUi(){
// ะขะฐะบะถะต, ะบะฐะบ ะธ ะฒ ะบะปะฐััะต ะฟัะธะปะพะถะตะฝะธั ัะพะทะดะฐะตะผ ะฟะพัั, ะพะฑะพัะฐัะธะฒะฐะตะผ ะฒ stream, ะดะตะปะฐะตะผ dnode
const backgroundPort = extensionApi.runtime.connect({name: 'popup'});
const connectionStream = new PortStream(backgroundPort);
const dnode = Dnode();
connectionStream.pipe(dnode).pipe(connectionStream);
const background = await new Promise(resolve => {
dnode.once('remote', api => {
resolve(api)
})
});
// ะะตะปะฐะตะผ ะพะฑัะตะบั API ะดะพัััะฟะฝัะผ ะธะท ะบะพะฝัะพะปะธ
if (DEV_MODE){
global.background = background;
}
}เชชเชเซ เช เชฎเซ เชธเชพเชฎเชเซเชฐเซ เชธเซเชเซเชฐเชฟเชชเซเชเชฎเชพเช เชเชจเซเชเซเชถเชจ เชฌเชจเชพเชตเซเช เชเซเช:
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import PostMessageStream from 'post-message-stream';
setupConnection();
injectScript();
function setupConnection(){
const backgroundPort = extensionApi.runtime.connect({name: 'contentscript'});
const backgroundStream = new PortStream(backgroundPort);
const pageStream = new PostMessageStream({
name: 'content',
target: 'page',
});
pageStream.pipe(backgroundStream).pipe(pageStream);
}
function injectScript(){
try {
// inject in-page script
let script = document.createElement('script');
script.src = extensionApi.extension.getURL('inpage.js');
const container = document.head || document.documentElement;
container.insertBefore(script, container.children[0]);
script.onload = () => script.remove();
} catch (e) {
console.error('Injection failed.', e);
}
}เช เชฎเชจเซ API เชจเซ เชเชฐเซเชฐ เชธเชพเชฎเชเซเชฐเซ เชธเซเชเซเชฐเชฟเชชเซเชเชฎเชพเช เชจเชฅเซ, เชชเชฐเชเชคเซ เชธเซเชงเชพ เชชเซเชทเซเช เชชเชฐ เชนเซเชตเชพเชฅเซ, เช เชฎเซ เชฌเซ เชตเชธเซเชคเซเช เชเชฐเซเช เชเซเช:
- เช
เชฎเซ เชฌเซ เชชเซเชฐเชตเชพเชนเซ เชฌเชจเชพเชตเซเช เชเซเช. เชเช - เชชเซเชทเซเช เชคเชฐเชซ, เชชเซเชธเซเชเชฎเซเชธเซเชเชจเซ เชเซเช เชชเชฐ. เช เชฎเชพเชเซ เช
เชฎเซ เชเชจเซ เชเชชเชฏเซเช เชเชฐเซเช เชเซเช เชฎเซเชเชพเชฎเชพเชธเซเชเชจเชพ เชจเชฟเชฐเซเชฎเชพเชคเชพเช เชคเชฐเชซเชฅเซ. เชฌเซเชเซ เชธเซเชเซเชฐเซเชฎ เชชเซเชฐเซเช เชชเชฐเชฅเซ เชฎเชณเซเชฒ เชชเซเชทเซเช เชญเซเชฎเชฟ เชชเชฐ เชเซ
runtime.connect. เชเชพเชฒเซ เชคเซเชฎเชจเซ เชเชฐเซเชฆเซเช. เชนเชตเซ เชชเซเชทเซเช เชชเซเชทเซเช เชญเซเชฎเชฟ เชชเชฐ เชเช เชธเซเชเซเชฐเซเชฎ เชนเชถเซ. - เชธเซเชเซเชฐเชฟเชชเซเชเชจเซ DOM เชฎเชพเช เชฆเชพเชเชฒ เชเชฐเซ. เชธเซเชเซเชฐเชฟเชชเซเช เชกเชพเชเชจเชฒเซเชก เชเชฐเซ (เชฎเซเชจเชฟเชซเซเชธเซเชเชฎเชพเช เชคเซเชจเซ เชเชเซเชธเซเชธเชจเซ เชฎเชเชเซเชฐเซ เชนเชคเซ) เช
เชจเซ เชเซเช เชฌเชจเชพเชตเซ
scriptเชคเซเชจเซ เช เชเชฆเชฐเชจเซ เชธเชพเชฎเชเซเชฐเซ เชธเชพเชฅเซ:
import PostMessageStream from 'post-message-stream';
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
setupConnection();
injectScript();
function setupConnection(){
// ะกััะธะผ ะบ ะฑะตะบะณัะฐัะฝะดั
const backgroundPort = extensionApi.runtime.connect({name: 'contentscript'});
const backgroundStream = new PortStream(backgroundPort);
// ะกััะธะผ ะบ ัััะฐะฝะธัะต
const pageStream = new PostMessageStream({
name: 'content',
target: 'page',
});
pageStream.pipe(backgroundStream).pipe(pageStream);
}
function injectScript(){
try {
// inject in-page script
let script = document.createElement('script');
script.src = extensionApi.extension.getURL('inpage.js');
const container = document.head || document.documentElement;
container.insertBefore(script, container.children[0]);
script.onload = () => script.remove();
} catch (e) {
console.error('Injection failed.', e);
}
}เชนเชตเซ เช เชฎเซ inpage เชฎเชพเช api เชเชฌเซเชเซเชเซเช เชฌเชจเชพเชตเซเช เชเซเช เช เชจเซ เชคเซเชจเซ เชตเซเชถเซเชตเชฟเช เชชเชฐ เชธเซเช เชเชฐเซเช เชเซเช:
import PostMessageStream from 'post-message-stream';
import Dnode from 'dnode/browser';
setupInpageApi().catch(console.error);
async function setupInpageApi() {
// ะกััะธะผ ะบ ะบะพะฝัะตะฝััะบัะธะฟัั
const connectionStream = new PostMessageStream({
name: 'page',
target: 'content',
});
const dnode = Dnode();
connectionStream.pipe(dnode).pipe(connectionStream);
// ะะพะปััะฐะตะผ ะพะฑัะตะบั API
const pageApi = await new Promise(resolve => {
dnode.once('remote', api => {
resolve(api)
})
});
// ะะพัััะฟ ัะตัะตะท window
global.SignerApp = pageApi;
}เช เชฎเซ เชคเซเชฏเชพเชฐ เชเซเช . เชจเชตเชพ เชชเซเชทเซเช เชจเซ เชชเซเชทเซเช เชญเซเชฎเชฟ เชธเชพเชฅเซ เชเชจเซเชเซเช เชเชฐเชคเซ เชตเชเชคเซ เชเชชเชฃเซ เช เชเซเช เชถเชเซเช เชเซเช:

เชเชพเชฒเซ API เช เชจเซ เชฎเซเชณ. เชชเซเชทเซเช เชฌเชพเชเซ เชชเชฐ, เชเชชเชฃเซ เชนเซเชฒเซ เชซเชเชเซเชถเชจเชจเซ เชเชจเชพ เชเซเชตเซเช เชเชนเซ เชถเชเซเช:

เชเชงเซเชจเชฟเช JS เชฎเชพเช เชเซเชฒเชฌเซเช เชซเชเชเซเชถเชจเซเชธ เชธเชพเชฅเซ เชเชพเชฎ เชเชฐเชตเซเช เช เชเชฐเชพเชฌ เชฐเซเชคเชญเชพเชค เชเซ, เชคเซเชฅเซ เชเชพเชฒเซ เชเช dnode เชฌเชจเชพเชตเชตเชพ เชฎเชพเชเซ เชเช เชจเชพเชจเซ เชธเชนเชพเชฏเช เชฒเชเซเช เชเซ เชคเชฎเชจเซ API เชเชฌเซเชเซเชเซเชเชจเซ utils เชชเชฐ เชชเชธเชพเชฐ เชเชฐเชตเชพเชจเซ เชฎเชเชเซเชฐเซ เชเชชเซ เชเซ.
API เชเชฌเซเชเซเชเซเช เชนเชตเซ เชเชจเชพ เชเซเชตเซ เชฆเซเชเชพเชถเซ:
export class SignerApp {
popupApi() {
return {
hello: async () => "world"
}
}
...
}เชฐเชฟเชฎเซเชเชฎเชพเชเชฅเซ เช เชฐเซเชคเซ เชเชฌเซเชเซเชเซเช เชฎเซเชณเชตเชตเซเช:
import {cbToPromise, transformMethods} from "../../src/utils/setupDnode";
const pageApi = await new Promise(resolve => {
dnode.once('remote', remoteApi => {
// ะก ะฟะพะผะพััั ััะธะปะธั ะผะตะฝัะตะผ ะฒัะต callback ะฝะฐ promise
resolve(transformMethods(cbToPromise, remoteApi))
})
});เช เชจเซ เชเซเชฒเชฟเชเช เชเชพเชฐเซเชฏเซ เชตเชเชจ เชเชชเซ เชเซ:

เช เชธเซเชฎเซเชณ เชเชพเชฐเซเชฏเซ เชธเชพเชฅเซเชจเซเช เชธเชเชธเซเชเชฐเชฃ เชเชชเชฒเชฌเซเชง เชเซ .
เชเชเชเชฆเชฐเซ, เชเชฐเชชเซเชธเซ เช เชจเซ เชธเซเชเซเชฐเซเชฎ เช เชญเชฟเชเชฎ เชเชเชฆเชฎ เชฒเชตเชเซเช เชฒเชพเชเซ เชเซ: เช เชฎเซ เชธเซเชเซเชฎ เชฎเชฒเซเชเชฟเชชเซเชฒเซเชเซเชธเชฟเชเชเชจเซ เชเชชเชฏเซเช เชเชฐเซ เชถเชเซเช เชเซเช เช เชจเซ เชตเชฟเชตเชฟเชง เชเชพเชฐเซเชฏเซ เชฎเชพเชเซ เชตเชฟเชตเชฟเชง API เชฌเชจเชพเชตเซ เชถเชเซเช เชเซเช. เชธเซเชฆเซเชงเชพเชเชคเชฟเช เชฐเซเชคเซ, เชกเซเชจเซเชกเชจเซ เชเชชเชฏเซเช เชเชฎเซ เชคเซเชฏเชพเช เชฅเช เชถเชเซ เชเซ, เชฎเซเชเซเชฏ เชตเชธเซเชคเซ เช เชจเซเชกเช เชธเซเชเซเชฐเซเชฎเชจเชพ เชธเซเชตเชฐเซเชชเชฎเชพเช เชชเชฐเชฟเชตเชนเชจเชจเซ เชฒเชชเซเชเซ เชเซ.
เชตเซเชเชฒเซเชชเชฟเช JSON เชซเซเชฐเซเชฎเซเช เชเซ, เชเซ JSON RPC 2 เชชเซเชฐเซเชเซเชเซเชฒเชจเซ เช เชฎเชฒ เชเชฐเซ เชเซ. เชเซ เชเซ, เชคเซ เชเซเชเซเชเชธ เชชเชฐเชฟเชตเชนเชจ (TCP เช เชจเซ HTTP(S)) เชธเชพเชฅเซ เชเชพเชฎ เชเชฐเซ เชเซ, เชเซ เช เชฎเชพเชฐเชพ เชเชฟเชธเซเชธเชพเชฎเชพเช เชฒเชพเชเซ เชชเชกเชคเซเช เชจเชฅเซ.
เชเชเชคเชฐเชฟเช เชฐเชพเชเซเชฏ เช เชจเซ เชธเซเชฅเชพเชจเชฟเช เชธเชเชเซเชฐเชน
เช เชฎเชพเชฐเซ เชเชชเซเชฒเชฟเชเซเชถเชจเชจเซ เชเชเชคเชฐเชฟเช เชธเซเชฅเชฟเชคเชฟ เชธเชเชเซเชฐเชนเชฟเชค เชเชฐเชตเชพเชจเซ เชเชฐเซเชฐ เชชเชกเชถเซ - เชเชเชพเชฎเชพเช เชเชเซ เชธเชพเชเชจเชฟเชเช เชเซ. เช เชฎเซ เชเชชเซเชฒเชฟเชเซเชถเชจเชฎเชพเช เชธเซเชฅเชฟเชคเชฟ เช เชจเซ เชคเซเชจเซ เชชเซเชชเช เชช API เชฎเชพเช เชฌเชฆเชฒเชตเชพ เชฎเชพเชเซเชจเซ เชชเชฆเซเชงเชคเชฟเช เชธเชฐเชณเชคเชพเชฅเซ เชเชฎเซเชฐเซ เชถเชเซเช เชเซเช:
import {setupDnode} from "./utils/setupDnode";
export class SignerApp {
constructor(){
this.store = {
keys: [],
};
}
addKey(key){
this.store.keys.push(key)
}
removeKey(index){
this.store.keys.splice(index,1)
}
popupApi(){
return {
addKey: async (key) => this.addKey(key),
removeKey: async (index) => this.removeKey(index)
}
}
...
} เชชเซเชทเซเช เชญเซเชฎเชฟเชฎเชพเช, เช เชฎเซ เชฆเชฐเซเช เชตเชธเซเชคเซเชจเซ เชซเชเชเซเชถเชจเชฎเชพเช เชฒเชชเซเชเซเชถเซเช เช เชจเซ เชเชชเซเชฒเชฟเชเซเชถเชจ เชเชฌเซเชเซเชเซเชเชจเซ เชตเชฟเชเชกเซเชฎเชพเช เชฒเชเซเชถเซเช เชเซเชฅเซ เช เชฎเซ เชเชจเซเชธเซเชฒเชฅเซ เชคเซเชจเซ เชธเชพเชฅเซ เชเชพเชฎ เชเชฐเซ เชถเชเซเช:
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";
const DEV_MODE = process.env.NODE_ENV !== 'production';
setupApp();
function setupApp() {
const app = new SignerApp();
if (DEV_MODE) {
global.app = app;
}
extensionApi.runtime.onConnect.addListener(connectRemote);
function connectRemote(remotePort) {
const processName = remotePort.name;
const portStream = new PortStream(remotePort);
if (processName === 'contentscript') {
const origin = remotePort.sender.url;
app.connectPage(portStream, origin)
} else {
app.connectPopup(portStream)
}
}
}เชเชพเชฒเซ UI เชเชจเซเชธเซเชฒเชฎเชพเชเชฅเซ เชฅเซเชกเซ เชเซ เชเชฎเซเชฐเซเช เช เชจเซ เชเซเชเช เชเซ เชฐเชพเชเซเชฏ เชธเชพเชฅเซ เชถเซเช เชฅเชพเชฏ เชเซ:

เชฐเชพเชเซเชฏเชจเซ เชธเชคเชค เชฌเชจเชพเชตเชตเชพเชจเซ เชเชฐเซเชฐ เชเซ เชเซเชฅเซ เชชเซเชจเชเชชเซเชฐเชพเชฐเชเชญ เชเชฐเชคเซ เชตเชเชคเซ เชเชพเชตเซเช เชเซเชตเชพเช เชจ เชเชพเชฏ.
เช เชฎเซ เชคเซเชจเซ เชฒเซเชเชฒ เชธเซเชเซเชฐเซเชเชฎเชพเช เชธเซเชเซเชฐ เชเชฐเซเชถเซเช, เชฆเชฐเซเช เชซเซเชฐเชซเชพเชฐ เชธเชพเชฅเซ เชคเซเชจเซ เชเชตเชฐเชฐเชพเชเช เชเชฐเซเชถเซเช. เชคเซเชฏเชพเชฐเชฌเชพเชฆ, UI เชฎเชพเชเซ เชชเชฃ เชคเซเชจเซ เชเชเซเชธเซเชธ เชเชฐเซเชฐเซ เชฐเชนเซเชถเซ, เช เชจเซ เชนเซเช เชซเซเชฐเชซเชพเชฐเซ เชฎเชพเชเซ เชธเชฌเซเชธเซเชเซเชฐเชพเชเชฌ เชเชฐเชตเชพ เชชเชฃ เชเชเซเชเซเช เชเซเช. เชคเซเชจเชพ เชเชงเชพเชฐเซ, เช เชตเชฒเซเชเชจเชเซเชทเชฎ เชธเซเชเซเชฐเซเช เชฌเชจเชพเชตเชตเชพ เช เชจเซ เชคเซเชจเชพ เชซเซเชฐเชซเชพเชฐเซ เชฎเชพเชเซ เชธเชฌเซเชธเซเชเซเชฐเชพเชเชฌ เชเชฐเชตเชพเชจเซเช เช เชจเซเชเซเชณ เชฐเชนเซเชถเซ.
เช เชฎเซ mobx เชชเซเชธเซเชคเชเชพเชฒเชฏเชจเซ เชเชชเชฏเซเช เชเชฐเซเชถเซเช (). เชชเชธเชเชฆเชเซ เชคเซเชจเชพ เชชเชฐ เชชเชกเซ เชเชพเชฐเชฃ เชเซ เชฎเชพเชฐเซ เชคเซเชจเซ เชธเชพเชฅเซ เชเชพเชฎ เชเชฐเชตเชพเชจเซ เชเชฐเซเชฐ เชจเชนเซเชคเซ, เชชเชฐเชเชคเซ เชนเซเช เชเชฐเซเชเชฐ เชคเซเชจเซ เช เชญเซเชฏเชพเชธ เชเชฐเชตเชพ เชฎเชพเชเชเชคเซ เชนเชคเซ.
เชเชพเชฒเซ เชชเซเชฐเชพเชฐเชเชญเชฟเช เชธเซเชฅเชฟเชคเชฟเชจเซ เชถเชฐเซเชเชค เชเชฎเซเชฐเซเช เช เชจเซ เชธเซเชเซเชฐเชจเซ เช เชตเชฒเซเชเชจเชเซเชทเชฎ เชฌเชจเชพเชตเซเช:
import {observable, action} from 'mobx';
import {setupDnode} from "./utils/setupDnode";
export class SignerApp {
constructor(initState = {}) {
// ะะฝะตัะฝะต store ัะฐะบ ะธ ะพััะฐะฝะตััั ัะตะผ ะถะต ะพะฑัะตะบัะพะผ, ัะพะปัะบะพ ัะตะฟะตัั ะฒัะต ะตะณะพ ะฟะพะปั ััะฐะปะธ proxy, ะบะพัะพััะต ะพััะปะตะถะธะฒะฐัั ะดะพัััะฟ ะบ ะฝะธะผ
this.store = observable.object({
keys: initState.keys || [],
});
}
// ะะตัะพะดั, ะบะพัะพััะต ะผะตะฝััั observable ะฟัะธะฝััะพ ะพะฑะพัะฐัะธะฒะฐัั ะดะตะบะพัะฐัะพัะพะผ
@action
addKey(key) {
this.store.keys.push(key)
}
@action
removeKey(index) {
this.store.keys.splice(index, 1)
}
...
}"เชนเซเชก เชนเซเช เชณ," mobx เช เชคเชฎเชพเชฎ เชธเซเชเซเชฐ เชซเซเชฒเซเชกเซเชธเชจเซ เชชเซเชฐเซเชเซเชธเซ เชธเชพเชฅเซ เชฌเชฆเชฒเซเชฏเชพ เชเซ เช เชจเซ เชคเซเชฎเชจเซ เชคเชฎเชพเชฎ เชเซเชฒเซเชธเชจเซ เช เชเชเชพเชตเซ เชเซ. เช เชธเชเชฆเซเชถเชพเช เชชเชฐ เชธเชฌเซเชธเซเชเซเชฐเชพเชเชฌ เชเชฐเชตเชพเชจเซเช เชถเชเซเชฏ เชฌเชจเชถเซ.
เชจเซเชเซ เชนเซเช เชเชฃเซ เชตเชพเชฐ "เชฌเชฆเชฒเชคเซ เชตเชเชคเซ" เชถเชฌเซเชฆเชจเซ เชเชชเชฏเซเช เชเชฐเซเชถ, เชเซ เชเซ เช เชธเชเชชเซเชฐเซเชฃ เชฐเซเชคเซ เชธเชพเชเซเช เชจเชฅเซ. Mobx เชซเซเชฒเซเชกเซเชธเชจเซ เชเชเซเชธเซเชธเชจเซ เชเซเชฐเซเช เชเชฐเซ เชเซ. เชฒเชพเชเชฌเซเชฐเซเชฐเซ เชเซ เชชเซเชฐเซเชเซเชธเซ เชเชฌเซเชเซเชเซเช เชฌเชจเชพเชตเซ เชเซ เชคเซเชจเชพ เชเซเชเชฐเซเชธ เช เชจเซ เชธเซเชเชฐเซเชธเชจเซ เชเชชเชฏเซเช เชฅเชพเชฏ เชเซ.
เชเชเซเชถเชจ เชกเซเชเซเชฐเซเชเชฐเซเชธ เชฌเซ เชนเซเชคเซเช เชชเซเชฐเชพ เชชเชพเชกเซ เชเซ:
- enforceActions เชซเซเชฒเซเช เชธเชพเชฅเซ เชเชกเช เชฎเซเชกเชฎเชพเช, mobx เชฐเชพเชเซเชฏเชจเซ เชธเซเชงเซเช เชฌเชฆเชฒเชตเชพ เชชเชฐ เชชเซเชฐเชคเชฟเชฌเชเชง เชฎเซเชเซ เชเซ. เชธเชเชค เชชเชฐเชฟเชธเซเชฅเชฟเชคเชฟเชเชฎเชพเช เชเชพเชฎ เชเชฐเชตเซเช เช เชธเชพเชฐเซ เชชเซเชฐเชฅเชพ เชฎเชพเชจเชตเชพเชฎเชพเช เชเชตเซ เชเซ.
- เชเซ เชเซเช เชซเชเชเซเชถเชจ เชเชฃเซ เชตเชเชค เชธเซเชเซเชเชฎเชพเช เชซเซเชฐเชซเชพเชฐ เชเชฐเซ เชคเซ เชชเชฃ - เชเชฆเชพเชนเชฐเชฃ เชคเชฐเซเชเซ, เช เชฎเซ เชเซเชกเชจเซ เชเซเชเชฒเซเช เชฒเชพเชเชจเชฎเชพเช เชเชฃเชพ เชซเซเชฒเซเชกเซเชธ เชฌเชฆเชฒเซเช เชเซเช - เชจเชฟเชฐเซเชเซเชทเชเซเชจเซ เชเซเชฏเชพเชฐเซ เชคเซ เชชเซเชฐเซเชฃ เชฅเชพเชฏ เชคเซเชฏเชพเชฐเซ เช เชธเซเชเชฟเชค เชเชฐเชตเชพเชฎเชพเช เชเชตเซ เชเซ. เช เช เชเซเชฐเชญเชพเช เชฎเชพเชเซ เชเชพเชธ เชเชฐเซเชจเซ เชฎเชนเชคเซเชตเชชเซเชฐเซเชฃ เชเซ, เชเซเชฏเชพเช เชฌเชฟเชจเชเชฐเซเชฐเซ เชธเซเชเซเช เช เชชเชกเซเช เชคเชคเซเชตเซเชจเชพ เชฌเชฟเชจเชเชฐเซเชฐเซ เชฐเซเชจเซเชกเชฐเชฟเชเช เชคเชฐเชซ เชฆเซเชฐเซ เชเชพเชฏ เชเซ. เช เชฎเชพเชฐเชพ เชเชฟเชธเซเชธเชพเชฎเชพเช, เชชเซเชฐเชฅเชฎ เชเซ เชฌเซเชเซเช เชฌเซเชฎเชพเชเชฅเซ เชเซเช เชเชพเชธ เชธเชเชฌเชเชงเชฟเชค เชจเชฅเซ, เชชเชฐเชเชคเซ เช เชฎเซ เชถเซเชฐเซเชทเซเช เชชเซเชฐเชฅเชพเชเชจเซเช เชชเชพเชฒเชจ เชเชฐเซเชถเซเช. เชคเซ เชคเชฎเชพเชฎ เชเชพเชฐเซเชฏเซเชฎเชพเช เชกเซเชเซเชฐเซเชเชฐเชจเซ เชเซเชกเชตเชพเชจเซ เชฐเชฟเชตเชพเช เชเซ เชเซ เช เชตเชฒเซเชเชจ เชเชฐเซเชฒ เชเซเชทเซเชคเซเชฐเซเชจเซ เชธเซเชฅเชฟเชคเชฟเชจเซ เชฌเชฆเชฒเซ เชเซ.
เชชเซเชทเซเช เชญเซเชฎเชฟเชฎเชพเช เช เชฎเซ เชฒเซเชเชฒ เชธเซเชเซเชฐเซเชเชฎเชพเช เชฐเชพเชเซเชฏเชจเซ เชเชฐเชเชญ เช เชจเซ เชธเชพเชเชตเซเชถเซเช:
import {reaction, toJS} from 'mobx';
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";
// ะัะฟะพะผะพะณะฐัะตะปัะฝัะต ะผะตัะพะดั. ะะฐะฟะธััะฒะฐัั/ัะธัะฐัั ะพะฑัะตะบั ะฒ/ะธะท localStorage ะฒะธะดะต JSON ัััะพะบะธ ะฟะพ ะบะปััั 'store'
import {loadState, saveState} from "./utils/localStorage";
const DEV_MODE = process.env.NODE_ENV !== 'production';
setupApp();
function setupApp() {
const initState = loadState();
const app = new SignerApp(initState);
if (DEV_MODE) {
global.app = app;
}
// Setup state persistence
// ะ ะตะทัะปััะฐั reaction ะฟัะธัะฒะฐะธะฒะฐะตััั ะฟะตัะตะผะตะฝะฝะพะน, ััะพะฑั ะฟะพะดะฟะธัะบั ะผะพะถะฝะพ ะฑัะปะพ ะพัะผะตะฝะธัั. ะะฐะผ ััะพ ะฝะต ะฝัะถะฝะพ, ะพััะฐะฒะปะตะฝะพ ะดะปั ะฟัะธะผะตัะฐ
const localStorageReaction = reaction(
() => toJS(app.store), // ะคัะฝะบัะธั-ัะตะปะตะบัะพั ะดะฐะฝะฝัั
saveState // ะคัะฝะบัะธั, ะบะพัะพัะฐั ะฑัะดะตั ะฒัะทะฒะฐะฝะฐ ะฟัะธ ะธะทะผะตะฝะตะฝะธะธ ะดะฐะฝะฝัั
, ะบะพัะพััะต ะฒะพะทะฒัะฐัะฐะตั ัะตะปะตะบัะพั
);
extensionApi.runtime.onConnect.addListener(connectRemote);
function connectRemote(remotePort) {
const processName = remotePort.name;
const portStream = new PortStream(remotePort);
if (processName === 'contentscript') {
const origin = remotePort.sender.url
app.connectPage(portStream, origin)
} else {
app.connectPopup(portStream)
}
}
}เชชเซเชฐเชคเชฟเชเซเชฐเชฟเชฏเชพ เชเชพเชฐเซเชฏ เช เชนเซเช เชฐเชธเชชเซเชฐเชฆ เชเซ. เชคเซเชจเซ เชฌเซ เชฆเชฒเซเชฒเซ เชเซ:
- เชกเซเชเชพ เชธเชฟเชฒเซเชเซเชเชฐ.
- เชเช เชนเซเชจเซเชกเชฒเชฐ เชเซ เชเซเชจเซ เช เชกเซเชเชพ เชฆเชฐ เชตเชเชคเซ เชฌเชฆเชฒเชพเชฏ เชคเซเชฏเชพเชฐเซ เชคเซเชจเซ เชธเชพเชฅเซ เชเซเชฒ เชเชฐเชตเชพเชฎเชพเช เชเชตเชถเซ.
เชฐเซเชกเชเซเชธเชฅเซ เชตเชฟเชชเชฐเซเชค, เชเซเชฏเชพเช เช เชฎเซ เชธเซเชชเชทเซเชเชชเชฃเซ เชฆเชฒเซเชฒ เชคเชฐเซเชเซ เชฐเชพเชเซเชฏ เชชเซเชฐเชพเชชเซเชค เชเชฐเซเช เชเซเช, mobx เชฏเชพเชฆ เชฐเชพเชเซ เชเซ เชเซ เช เชฎเซ เชชเชธเชเชฆเชเซเชเชพเชฐเชจเซ เช เชเชฆเชฐ เชเชฏเชพ เช เชตเชฒเซเชเชจเชเซเชทเชฎ เชตเชธเซเชคเซเชเชจเซ เชเชเซเชธเซเชธ เชเชฐเซเช เชเซเช, เช เชจเซ เชเซเชฏเชพเชฐเซ เชคเซเช เชฌเชฆเชฒเชพเชฏ เชเซ เชคเซเชฏเชพเชฐเซ เช เชนเซเชจเซเชกเชฒเชฐเชจเซ เชเซเชฒ เชเชฐเซ เชเซ.
เชคเซ เชธเชฎเชเชตเซเช เช
เชเชคเซเชฏเชจเซเช เชเซ เชเซ mobx เชเซเชตเซ เชฐเซเชคเซ เชจเชเซเชเซ เชเชฐเซ เชเซ เชเซ เชเชชเชฃเซ เชเชฏเชพ เช
เชตเชฒเซเชเชจเชเซเชทเชฎ เชชเชฐ เชธเชฌเซเชธเซเชเซเชฐเชพเชเชฌ เชเชฐเซเช เชเซเช. เชเซ เชฎเซเช เชเชจเชพ เชเซเชตเชพ เชเซเชกเชฎเชพเช เชชเชธเชเชฆเชเซเชเชพเชฐ เชฒเชเซเชฏเซเช() => app.store, เชคเซ เชชเชเซ เชชเซเชฐเชคเชฟเชเซเชฐเชฟเชฏเชพ เชเซเชฏเชพเชฐเซเชฏ เชเชนเซเชตเชพเชถเซ เชจเชนเซเช, เชเชพเชฐเชฃ เชเซ เชธเชเชเซเชฐเชน เชชเซเชคเซ เช
เชตเชฒเซเชเชจเชเซเชทเชฎ เชจเชฅเซ, เชซเชเซเชค เชคเซเชจเชพ เชเซเชทเซเชคเซเชฐเซ เชเซ.
เชเซ เชฎเซเช เชคเซเชจเซ เช เชฐเซเชคเซ เชฒเชเซเชฏเซเช () => app.store.keys, เชชเชเซ เชซเชฐเซเชฅเซ เชเชเช เชฅเชถเซ เชจเชนเซเช, เชเชพเชฐเชฃ เชเซ เชเซเชฏเชพเชฐเซ เชเชฐเซ เชคเชคเซเชตเซ เชเชฎเซเชฐเซ/เชฆเซเชฐ เชเชฐเซ เชฐเชนเซเชฏเชพ เชนเซเชฏ, เชคเซเชฏเชพเชฐเซ เชคเซเชจเซ เชธเชเชฆเชฐเซเชญ เชฌเชฆเชฒเชพเชถเซ เชจเชนเซเช.
Mobx เชชเซเชฐเชฅเชฎ เชตเชเชค เชชเชธเชเชฆเชเซเชเชพเชฐ เชคเชฐเซเชเซ เชเชพเชฐเซเชฏ เชเชฐเซ เชเซ เช
เชจเซ เชฎเชพเชคเซเชฐ เช
เชฎเซ เชเชเซเชธเซเชธ เชเชฐเซเชฒ เช
เชตเชฒเซเชเชจเชเซเชทเชฎ เชตเชธเซเชคเซเชเชจเซ เช เชเซเชฐเซ
เช เชฐเชพเชเซ เชเซ. เช เชชเซเชฐเซเชเซเชธเซ เชเซเชเชฐ เชฆเซเชตเชพเชฐเชพ เชเชฐเชตเชพเชฎเชพเช เชเชตเซ เชเซ. เชคเซเชฅเซ, เชฌเชฟเชฒเซเช-เชเชจ เชซเชเชเซเชถเชจเชจเซ เชเชชเชฏเซเช เช
เชนเซเช เชฅเชพเชฏ เชเซ toJS. เชคเซ เชฎเซเชณ เชเซเชทเซเชคเซเชฐเซ เชธเชพเชฅเซ เชฌเชฆเชฒเชพเชฏเซเชฒ เชคเชฎเชพเชฎ เชชเซเชฐเซเชเซเชธเซเช เชธเชพเชฅเซ เชเช เชจเชตเซ เชเชฌเซเชเซเชเซเช เชชเชฐเชค เชเชฐเซ เชเซ. เชเชเซเชเซเชเซเชฏเซเชถเชจ เชฆเชฐเชฎเชฟเชฏเชพเชจ, เชคเซ เชเชฌเซเชเซเชเซเชเชจเชพ เชคเชฎเชพเชฎ เชเซเชทเซเชคเซเชฐเซเชจเซ เชตเชพเชเชเซ เชเซ - เชคเซเชฅเซ เชเซเชเชฐเซเชธ เชเซเชฐเชฟเชเชฐ เชฅเชพเชฏ เชเซ.
เชชเซเชชเช เชช เชเชจเซเชธเซเชฒเชฎเชพเช เชเชชเชฃเซ เชซเชฐเซเชฅเซ เชเชฃเซ เชเซ เชเชฎเซเชฐเซเชถเซเช. เช เชตเชเชคเซ เชคเซเช เชฒเซเชเชฒ เชธเซเชเซเชฐเซเชเชฎเชพเช เชชเชฃ เชธเชฎเชพเชชเซเชค เชฅเชฏเชพ:

เชเซเชฏเชพเชฐเซ เชชเซเชทเซเช เชญเซเชฎเชฟ เชชเซเชทเซเช เชซเชฐเซเชฅเซ เชฒเซเชก เชฅเชพเชฏ เชเซ, เชคเซเชฏเชพเชฐเซ เชฎเชพเชนเชฟเชคเซ เชธเซเชฅเชพเชจเซ เชฐเชนเซ เชเซ.
เช เชฌเชฟเชเชฆเซ เชธเซเชงเซเชจเชพ เชคเชฎเชพเชฎ เชเชชเซเชฒเชฟเชเซเชถเชจ เชเซเชก เชเซเช เชถเชเชพเชฏ เชเซ .
เชเชพเชจเชเซ เชเซเชเชจเซ เชธเซเชฐเชเซเชทเชฟเชค เชธเชเชเซเชฐเชน
เชธเซเชชเชทเซเช เชฒเชเชพเชฃเชฎเชพเช เชเชพเชจเชเซ เชเซเชจเซ เชธเชเชเซเชฐเชนเชฟเชค เชเชฐเชตเซ เช เชธเซเชฐเชเซเชทเชฟเชค เชเซ: เชคเชฎเชจเซ เชนเซเช เชเชฐเชตเชพเชฎเชพเช เชเชตเชถเซ, เชคเชฎเชพเชฐเชพ เชเซเชฎเซเชชเซเชฏเซเชเชฐเชจเซ เชเชเซเชธเซเชธ เชฎเซเชณเชตเซ, เชตเชเซเชฐเซ เชเชตเซ เชถเชเซเชฏเชคเชพ เชนเชเชฎเซเชถเชพ เชฐเชนเซ เชเซ. เชคเซเชฅเซ, เชฒเซเชเชฒ เชธเซเชเซเชฐเซเชเชฎเชพเช เชเชชเชฃเซ เชเซเชจเซ เชชเชพเชธเชตเชฐเซเชก-เชเชจเซเชเซเชฐเชฟเชชเซเชเซเชก เชธเซเชตเชฐเซเชชเชฎเชพเช เชธเชเชเซเชฐเชนเชฟเชค เชเชฐเซเชถเซเช.
เชตเชงเซ เชธเซเชฐเชเซเชทเชพ เชฎเชพเชเซ, เช เชฎเซ เชเชชเซเชฒเชฟเชเซเชถเชจเชฎเชพเช เชเช เชฒเซเช เชเชฐเซเชฒเซ เชธเซเชฅเชฟเชคเชฟ เชเชฎเซเชฐเซเชถเซเช, เชเซเชฎเชพเช เชเชพเชตเซเชเชจเซ เชฌเชฟเชฒเชเซเชฒ เชเชเซเชธเซเชธ เชนเชถเซ เชจเชนเซเช. เชธเชฎเชฏ เชธเชฎเชพเชชเซเชค เชฅเชตเชพเชจเซ เชเชพเชฐเชฃเซ เช เชฎเซ เชเชเซเชธเซเชเซเชเชถเชจเชจเซ เชฒเซเช เชเชฐเซเชฒ เชธเซเชฅเชฟเชคเชฟเชฎเชพเช เชเชชเชฎเซเชณเซ เชธเซเชฅเชพเชจเชพเชเชคเชฐเชฟเชค เชเชฐเซเชถเซเช.
Mobx เชคเชฎเชจเซ เชกเซเชเชพเชจเชพ เชจเซเชฏเซเชจเชคเชฎ เชธเซเชเชจเซ เชธเชเชเซเชฐเชนเชฟเชค เชเชฐเชตเชพเชจเซ เชฎเชเชเซเชฐเซ เชเชชเซ เชเซ, เช เชจเซ เชฌเชพเชเซเชจเซ เชเชชเชฎเซเชณเซ เชคเซเชจเชพ เชเชงเชพเชฐเซ เชเชฃเชคเชฐเซ เชเชฐเชตเชพเชฎเชพเช เชเชตเซ เชเซ. เช เชเชนเซเชตเชพเชคเชพ เชเชฃเชฟเชค เชเซเชฃเชงเชฐเซเชฎเซ เชเซ. เชคเซเชฎเชจเซ เชคเซเชฒเชจเชพ เชกเซเชเชพเชฌเซเชเชฎเชพเช เชเซเชตเชพเช เชธเชพเชฅเซ เชเชฐเซ เชถเชเชพเชฏ เชเซ:
import {observable, action} from 'mobx';
import {setupDnode} from "./utils/setupDnode";
// ะฃัะธะปะธัั ะดะปั ะฑะตะทะพะฟะฐัะฝะพะณะพ ัะธััะพะฒะฐะฝะธั ัััะพะบ. ะัะฟะพะปัะทััั crypto-js
import {encrypt, decrypt} from "./utils/cryptoUtils";
export class SignerApp {
constructor(initState = {}) {
this.store = observable.object({
// ะฅัะฐะฝะธะผ ะฟะฐัะพะปั ะธ ะทะฐัะธััะพะฒะฐะฝะฝัะต ะบะปััะธ. ะัะปะธ ะฟะฐัะพะปั null - ะฟัะธะปะพะถะตะฝะธะต locked
password: null,
vault: initState.vault,
// ะะตััะตัั ะดะปั ะฒััะธัะปะธะผัั
ะฟะพะปะตะน. ะะพะถะฝะพ ะฟัะพะฒะตััะธ ะฐะฝะฐะปะพะณะธั ั view ะฒ ะฑะด.
get locked(){
return this.password == null
},
get keys(){
return this.locked ?
undefined :
SignerApp._decryptVault(this.vault, this.password)
},
get initialized(){
return this.vault !== undefined
}
})
}
// ะะฝะธัะธะฐะปะธะทะฐัะธั ะฟัััะพะณะพ ั
ัะฐะฝะธะปะธัะฐ ะฝะพะฒัะผ ะฟะฐัะพะปะตะผ
@action
initVault(password){
this.store.vault = SignerApp._encryptVault([], password)
}
@action
lock() {
this.store.password = null
}
@action
unlock(password) {
this._checkPassword(password);
this.store.password = password
}
@action
addKey(key) {
this._checkLocked();
this.store.vault = SignerApp._encryptVault(this.store.keys.concat(key), this.store.password)
}
@action
removeKey(index) {
this._checkLocked();
this.store.vault = SignerApp._encryptVault([
...this.store.keys.slice(0, index),
...this.store.keys.slice(index + 1)
],
this.store.password
)
}
... // ะบะพะด ะฟะพะดะบะปััะตะฝะธั ะธ api
// private
_checkPassword(password) {
SignerApp._decryptVault(this.store.vault, password);
}
_checkLocked() {
if (this.store.locked){
throw new Error('App is locked')
}
}
// ะะตัะพะดั ะดะปั ัะธััะพะฒะบะธ/ะดะตัะธััะพะฒะบะธ ั
ัะฐะฝะธะปะธัะฐ
static _encryptVault(obj, pass){
const jsonString = JSON.stringify(obj)
return encrypt(jsonString, pass)
}
static _decryptVault(str, pass){
if (str === undefined){
throw new Error('Vault not initialized')
}
try {
const jsonString = decrypt(str, pass)
return JSON.parse(jsonString)
}catch (e) {
throw new Error('Wrong password')
}
}
}เชนเชตเซ เช เชฎเซ เชซเชเซเชค เชเชจเซเชเซเชฐเชฟเชชเซเชเซเชก เชเซ เช เชจเซ เชชเชพเชธเชตเชฐเซเชก เชธเซเชเซเชฐ เชเชฐเซเช เชเซเช. เชฌเชพเชเซเชจเซเช เชฌเชงเซเช เชเชฃเชพเชฏ เชเซ. เช เชฎเซ เชฐเชพเชเซเชฏเชฎเชพเชเชฅเซ เชชเชพเชธเชตเชฐเซเชก เชฆเซเชฐ เชเชฐเซเชจเซ เชฒเซเช เชเชฐเซเชฒเซ เชธเซเชฅเชฟเชคเชฟเชฎเชพเช เชเซเชฐเชพเชจเซเชธเชซเชฐ เชเชฐเซเช เชเซเช. เชธเชพเชฐเซเชตเชเชจเชฟเช API เชชเชพเชธเซ เชนเชตเซ เชธเซเชเซเชฐเซเช เชถเชฐเซ เชเชฐเชตเชพเชจเซ เชชเชฆเซเชงเชคเชฟ เชเซ.
เชเชจเซเชเซเชฐเชฟเชชเซเชถเชจ เชฎเชพเชเซ เชฒเชเชพเชฏเซเชฒ :
import CryptoJS from 'crypto-js'
// ะัะฟะพะปัะทัะตััั ะดะปั ะพัะปะพะถะฝะตะฝะธั ะฟะพะดะฑะพัะฐ ะฟะฐัะพะปั ะฟะตัะตะฑะพัะพะผ. ะะฐ ะบะฐะถะดัะน ะฒะฐัะธะฐะฝั ะฟะฐัะพะปั ะทะปะพัะผััะปะตะฝะฝะธะบั ะฟัะธะดะตััั ัะดะตะปะฐัั 5000 ั
ะตัะตะน
function strengthenPassword(pass, rounds = 5000) {
while (rounds-- > 0){
pass = CryptoJS.SHA256(pass).toString()
}
return pass
}
export function encrypt(str, pass){
const strongPass = strengthenPassword(pass);
return CryptoJS.AES.encrypt(str, strongPass).toString()
}
export function decrypt(str, pass){
const strongPass = strengthenPassword(pass)
const decrypted = CryptoJS.AES.decrypt(str, strongPass);
return decrypted.toString(CryptoJS.enc.Utf8)
}เชฌเซเชฐเชพเชเชเชฐเชฎเชพเช เชเช เชจเชฟเชทเซเชเซเชฐเชฟเชฏ API เชเซ เชเซเชจเชพ เชฆเซเชตเชพเชฐเชพ เชคเชฎเซ เชเชตเซเชจเซเชเชฎเชพเช เชธเชฌเซเชธเซเชเซเชฐเชพเชเชฌ เชเชฐเซ เชถเชเซ เชเซ - เชธเซเชเซเช เชซเซเชฐเชซเชพเชฐเซ. เชฐเชพเชเซเชฏ, เชคเซ เชฎเซเชเชฌ, เชนเซเช เชถเชเซ เชเซ idle, active ะธ locked. เชจเชฟเชทเซเชเซเชฐเชฟเชฏ เชฎเชพเชเซ เชคเชฎเซ เชธเชฎเชฏเชธเชฎเชพเชชเซเชคเชฟ เชธเซเช เชเชฐเซ เชถเชเซ เชเซ, เช
เชจเซ เชเซเชฏเชพเชฐเซ OS เชชเซเชคเซ เช เช
เชตเชฐเซเชงเชฟเชค เชนเซเชฏ เชคเซเชฏเชพเชฐเซ เชฒเซเช เชธเซเช เชฅเชพเชฏ เชเซ. เช
เชฎเซ เชฒเซเชเชฒ เชธเซเชเซเชฐเซเชเชฎเชพเช เชธเชพเชเชตเชตเชพ เชฎเชพเชเซ เชชเชธเชเชฆเชเซเชเชพเชฐเชจเซ เชชเชฃ เชฌเชฆเชฒเซเชถเซเช:
import {reaction, toJS} from 'mobx';
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";
import {loadState, saveState} from "./utils/localStorage";
const DEV_MODE = process.env.NODE_ENV !== 'production';
const IDLE_INTERVAL = 30;
setupApp();
function setupApp() {
const initState = loadState();
const app = new SignerApp(initState);
if (DEV_MODE) {
global.app = app;
}
// ะขะตะฟะตัั ะผั ัะฒะฝะพ ัะทัะฒะฐะตะผ ะฟะพะปะต, ะบะพัะพัะพะผั ะฑัะดะตั ะฟัะพะธัั
ะพะดะธัั ะดะพัััะฟ, reaction ะพััะฐะฑะพัะฐะตั ะฝะพัะผะฐะปัะฝะพ
reaction(
() => ({
vault: app.store.vault
}),
saveState
);
// ะขะฐะนะผะฐัั ะฑะตะทะดะตะนััะฒะธั, ะบะพะณะดะฐ ััะฐะฑะพัะฐะตั ัะพะฑััะธะต
extensionApi.idle.setDetectionInterval(IDLE_INTERVAL);
// ะัะปะธ ะฟะพะปัะทะพะฒะฐัะตะปั ะทะฐะปะพัะธะป ัะบัะฐะฝ ะธะปะธ ะฑะตะทะดะตะนััะฒะพะฒะฐะป ะฒ ัะตัะตะฝะธะต ัะบะฐะทะฐะฝะฝะพะณะพ ะธะฝัะตัะฒะฐะปะฐ ะปะพัะธะผ ะฟัะธะปะพะถะตะฝะธะต
extensionApi.idle.onStateChanged.addListener(state => {
if (['locked', 'idle'].indexOf(state) > -1) {
app.lock()
}
});
// Connect to other contexts
extensionApi.runtime.onConnect.addListener(connectRemote);
function connectRemote(remotePort) {
const processName = remotePort.name;
const portStream = new PortStream(remotePort);
if (processName === 'contentscript') {
const origin = remotePort.sender.url
app.connectPage(portStream, origin)
} else {
app.connectPopup(portStream)
}
}
}เช เชชเชเชฒเชพ เชชเชนเซเชฒเชพเชจเซ เชเซเชก เชเซ .
เชตเซเชฏเชตเชนเชพเชฐ
เชคเซเชฅเซ, เช เชฎเซ เชธเซเชฅเซ เชฎเชนเชคเซเชตเชจเซ เชฌเชพเชฌเชค เชชเชฐ เชเชตเซเช เชเซเช: เชฌเซเชฒเซเชเชเซเชจ เชชเชฐ เชตเซเชฏเชตเชนเชพเชฐเซ เชฌเชจเชพเชตเชตเชพ เช เชจเซ เชนเชธเซเชคเชพเชเซเชทเชฐ เชเชฐเชตเชพ. เช เชฎเซ WAVES เชฌเซเชฒเซเชเชเซเชจ เช เชจเซ เชฒเชพเชเชฌเซเชฐเซเชฐเซเชจเซ เชเชชเชฏเซเช เชเชฐเซเชถเซเช .
เชชเซเชฐเชฅเชฎ, เชเชพเชฒเซ เชฐเชพเชเซเชฏเชฎเชพเช เชธเชเชฆเซเชถเชพเชเชจเซ เชถเซเชฐเซเชฃเซ เชเชฎเซเชฐเซเช เชเซ เชเซเชจเชพ เชชเชฐ เชธเชนเซ เชเชฐเชตเชพเชจเซ เชเชฐเซเชฐ เชเซ, เชชเชเซ เชจเชตเซ เชธเชเชฆเซเชถ เชเชฎเซเชฐเชตเชพ, เชนเชธเซเชคเชพเชเซเชทเชฐเชจเซ เชชเซเชทเซเชเชฟ เชเชฐเชตเชพ เช เชจเซ เชจเชเชพเชฐเชตเชพ เชฎเชพเชเซเชจเซ เชชเชฆเซเชงเชคเชฟเช เชเชฎเซเชฐเซ:
import {action, observable, reaction} from 'mobx';
import uuid from 'uuid/v4';
import {signTx} from '@waves/waves-transactions'
import {setupDnode} from "./utils/setupDnode";
import {decrypt, encrypt} from "./utils/cryptoUtils";
export class SignerApp {
...
@action
newMessage(data, origin) {
// ะะปั ะบะฐะถะดะพะณะพ ัะพะพะฑัะตะฝะธั ัะพะทะดะฐะตะผ ะผะตัะฐะดะฐะฝะฝัะต ั id, ััะฐัััะพะผ, ะฒััะตะผะตะฝะตะผ ัะพะทะดะฐะฝะธั ะธ ัะด.
const message = observable.object({
id: uuid(), // ะะดะตะฝัะธัะธะบะฐัะพั, ะธัะฟะพะปัะทััั uuid
origin, // Origin ะฑัะดะตะผ ะฒะฟะพัะปะตะดััะฒะธะธ ะฟะพะบะฐะทัะฒะฐัั ะฒ ะธะฝัะตััะตะนัะต
data, //
status: 'new', // ะกัะฐัััะพะฒ ะฑัะดะตั ัะตัััะต: new, signed, rejected ะธ failed
timestamp: Date.now()
});
console.log(`new message: ${JSON.stringify(message, null, 2)}`);
this.store.messages.push(message);
// ะะพะทะฒัะฐัะฐะตะผ ะฟัะพะผะธั ะฒะฝัััะธ ะบะพัะพัะพะณะพ mobx ะผะพะฝะธัะพัะธั ะธะทะผะตะฝะตะฝะธั ัะพะพะฑัะตะฝะธั. ะะฐะบ ัะพะปัะบะพ ััะฐััั ะฟะพะผะตะฝัะตััั ะผั ะทะฐัะตะทะพะปะฒะธะผ ะตะณะพ
return new Promise((resolve, reject) => {
reaction(
() => message.status, //ะัะดะตะผ ะพะฑัะตัะฒะธัั ััะฐััั ัะพะพะฑัะตะฝั
(status, reaction) => { // ะฒัะพัะพะน ะฐัะณัะผะตะฝั ััะพ ัััะปะบะฐ ะฝะฐ ัะฐะผ reaction, ััะพะฑั ะตะณะพ ะผะพะถะฝะพ ะฑัะปะพ ัะฝะธััะพะถัั ะฒะฝัััะธ ะฒัะทะพะฒะฐ
switch (status) {
case 'signed':
resolve(message.data);
break;
case 'rejected':
reject(new Error('User rejected message'));
break;
case 'failed':
reject(new Error(message.err.message));
break;
default:
return
}
reaction.dispose()
}
)
})
}
@action
approve(id, keyIndex = 0) {
const message = this.store.messages.find(msg => msg.id === id);
if (message == null) throw new Error(`No msg with id:${id}`);
try {
message.data = signTx(message.data, this.store.keys[keyIndex]);
message.status = 'signed'
} catch (e) {
message.err = {
stack: e.stack,
message: e.message
};
message.status = 'failed'
throw e
}
}
@action
reject(id) {
const message = this.store.messages.find(msg => msg.id === id);
if (message == null) throw new Error(`No msg with id:${id}`);
message.status = 'rejected'
}
...
}เชเซเชฏเชพเชฐเซ เช
เชฎเชจเซ เชจเชตเซ เชธเชเชฆเซเชถ เชฎเชณเซ เชเซ, เชคเซเชฏเชพเชฐเซ เช
เชฎเซ เชคเซเชฎเชพเช เชฎเซเชเชพเชกเซเชเชพ เชเชฎเซเชฐเซเช เชเซเช, เชเชฐเซ observable เช
เชจเซ เชเชฎเซเชฐเซ store.messages.
เชเซ เชคเชฎเซ เชจเชพ เชเชฐเซ observable เชฎเซเชจเซเชฏเซเช
เชฒเซ, เชชเชเซ เชเชฐเซเชฎเชพเช เชธเชเชฆเซเชถเชพเช เชเชฎเซเชฐเชคเซ เชตเชเชคเซ mobx เชคเซ เชชเซเชคเซ เชเชฐเชถเซ. เชเซ เชเซ, เชคเซ เชเช เชจเชตเซ เชเชฌเซเชเซเชเซเช เชฌเชจเชพเชตเชถเซ เชเซเชจเซ เช
เชฎเชพเชฐเซ เชชเชพเชธเซ เชเซเช เชธเชเชฆเชฐเซเชญ เชจเชฅเซ, เชชเชฐเชเชคเซ เช
เชฎเชจเซ เชเชเชฒเชพ เชชเชเชฒเชพ เชฎเชพเชเซ เชคเซเชจเซ เชเชฐเซเชฐ เชชเชกเชถเซ.
เชเชเชณ, เช เชฎเซ เชเช เชตเชเชจ เชชเชฐเชค เชเชฐเซเช เชเซเช เชเซ เชธเชเชฆเซเชถเชจเซ เชธเซเชฅเชฟเชคเชฟ เชฌเชฆเชฒเชพเชฏ เชคเซเชฏเชพเชฐเซ เชเชเซเชฒเชพเช เชเชพเชฏ เชเซ. เชชเซเชฐเชคเชฟเชเซเชฐเชฟเชฏเชพ เชฆเซเชตเชพเชฐเชพ เชธเซเชฅเชฟเชคเชฟเชจเซเช เชจเชฟเชฐเซเชเซเชทเชฃ เชเชฐเชตเชพเชฎเชพเช เชเชตเซ เชเซ, เชเซ เชธเซเชฅเชฟเชคเชฟ เชฌเชฆเชฒเชพเชฏ เชคเซเชฏเชพเชฐเซ "เชชเซเชคเชพเชจเซ เชฎเชพเชฐเซ เชจเชพเชเชถเซ".
เชชเชฆเซเชงเชคเชฟ เชเซเชก approve ะธ reject เชเซเชฌ เช เชธเชฐเชณ: เชเซ เชเชฐเซเชฐเซ เชนเซเชฏ เชคเซ เชธเชพเชเชจ เชเชฐเซเชฏเชพ เชชเชเซ, เช
เชฎเซ เชซเชเซเชค เชธเชเชฆเซเชถเชจเซ เชธเซเชฅเชฟเชคเชฟ เชฌเชฆเชฒเซเช เชเซเช.
เช เชฎเซ UI API เชฎเชพเช เชฎเชเชเซเชฐ เช เชจเซ เช เชธเซเชตเซเชเชพเชฐ เชฎเซเชเซเช เชเซเช, เชชเซเช API เชฎเชพเช เชจเชตเซ เชธเชเชฆเซเชถ:
export class SignerApp {
...
popupApi() {
return {
addKey: async (key) => this.addKey(key),
removeKey: async (index) => this.removeKey(index),
lock: async () => this.lock(),
unlock: async (password) => this.unlock(password),
initVault: async (password) => this.initVault(password),
approve: async (id, keyIndex) => this.approve(id, keyIndex),
reject: async (id) => this.reject(id)
}
}
pageApi(origin) {
return {
signTransaction: async (txParams) => this.newMessage(txParams, origin)
}
}
...
}เชนเชตเซ เชเชพเชฒเซ เชเชเซเชธเซเชเซเชเชถเชจ เชธเชพเชฅเซ เชเซเชฐเชพเชจเซเชเซเชเซเชถเชจ เชชเชฐ เชธเชนเซ เชเชฐเชตเชพเชจเซ เชชเซเชฐเชฏเชพเชธ เชเชฐเซเช:

เชธเชพเชฎเชพเชจเซเชฏ เชฐเซเชคเซ, เชฌเชงเซเช เชคเซเชฏเชพเชฐ เชเซ, เชเซ เชฌเชพเชเซ เชเซ เชคเซ เชเซ .
UI
เชเชจเซเชเชฐเชซเซเชธเชจเซ เชเชชเซเชฒเชฟเชเซเชถเชจ เชธเซเชเซเชเชจเซ เชเชเซเชธเซเชธเชจเซ เชเชฐเซเชฐ เชเซ. UI เชฌเชพเชเซเช เช
เชฎเซ เชเชฐเซเชถเซเช observable เชธเซเชเซเช เชเชฐเซ เช
เชจเซ API เชฎเชพเช เชซเชเชเซเชถเชจ เชเชฎเซเชฐเซ เชเซ เช เชธเซเชฅเชฟเชคเชฟเชจเซ เชฌเชฆเชฒเชถเซ. เชเชพเชฒเซ เชเชฎเซเชฐเซเช observable เชชเซเชทเซเช เชญเซเชฎเชฟเชฎเชพเชเชฅเซ เชชเซเชฐเชพเชชเซเชค API เชเชฌเซเชเซเชเซเช เชชเชฐ:
import {observable} from 'mobx'
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {cbToPromise, setupDnode, transformMethods} from "./utils/setupDnode";
import {initApp} from "./ui/index";
const DEV_MODE = process.env.NODE_ENV !== 'production';
setupUi().catch(console.error);
async function setupUi() {
// ะะพะดะบะปััะฐะตะผัั ะบ ะฟะพััั, ัะพะทะดะฐะตะผ ะธะท ะฝะตะณะพ ัััะธะผ
const backgroundPort = extensionApi.runtime.connect({name: 'popup'});
const connectionStream = new PortStream(backgroundPort);
// ะกะพะทะดะฐะตะผ ะฟัััะพะน observable ะดะปั ัะพััะพัะฝะธั background'a
let backgroundState = observable.object({});
const api = {
//ะัะดะฐะตะผ ะฑะตะบะณัะฐัะฝะดั ััะฝะบัะธั, ะบะพัะพัะฐั ะฑัะดะตั ะพะฑะฝะพะฒะปััั observable
updateState: async state => {
Object.assign(backgroundState, state)
}
};
// ะะตะปะฐะตะผ RPC ะพะฑัะตะบั
const dnode = setupDnode(connectionStream, api);
const background = await new Promise(resolve => {
dnode.once('remote', remoteApi => {
resolve(transformMethods(cbToPromise, remoteApi))
})
});
// ะะพะฑะฐะฒะปัะตะผ ะฒ background observable ัะพ ััะตะนัะพะผ
background.state = backgroundState;
if (DEV_MODE) {
global.background = background;
}
// ะะฐะฟััะบ ะธะฝัะตััะตะนัะฐ
await initApp(background)
}
เช เชเชคเซ เช เชฎเซ เชเชชเซเชฒเชฟเชเซเชถเชจ เชเชจเซเชเชฐเชซเซเชธ เชฐเซเชจเซเชกเชฐ เชเชฐเชตเชพเชจเซเช เชถเชฐเซ เชเชฐเซเช เชเซเช. เช เชเช เชฐเชฟเชเชเซเช เชเชชเซเชฒเชฟเชเซเชถเชจ เชเซ. เชชเซเชทเซเช เชญเซเชฎเชฟ เชเชฌเซเชเซเชเซเช เชชเซเชฐเซเชชเซเชธเชจเซ เชเชชเชฏเซเช เชเชฐเซเชจเซ เชธเชฐเชณ เชฐเซเชคเซ เชชเชธเชพเชฐ เชฅเชพเชฏ เชเซ. เชคเซ เชธเชพเชเซเช เชนเชถเซ, เช เชฒเชฌเชคเซเชค, เชชเชฆเซเชงเชคเชฟเช เชฎเชพเชเซ เชเช เช เชฒเช เชธเซเชตเชพ เช เชจเซ เชฐเชพเชเซเชฏ เชฎเชพเชเซ เชธเซเชเซเชฐ เชฌเชจเชพเชตเชตเซ, เชชเชฐเชเชคเซ เช เชฒเซเชเชจเชพ เชนเซเชคเซเช เชฎเชพเชเซ เช เชชเซเชฐเชคเซเช เชเซ:
import {render} from 'react-dom'
import App from './App'
import React from "react";
// ะะฝะธัะธะฐะปะธะทะธััะตะผ ะฟัะธะปะพะถะตะฝะธะต ั background ะพะฑัะตะบัะพะผ ะฒ ะบะฐัะตัั ะฒะต props
export async function initApp(background){
render(
<App background={background}/>,
document.getElementById('app-content')
);
}
เชเซเชฏเชพเชฐเซ เชกเซเชเชพ เชฌเชฆเชฒเชพเชฏ เชคเซเชฏเชพเชฐเซ เชฐเซเชจเซเชกเชฐเชฟเชเช เชถเชฐเซ เชเชฐเชตเซเช mobx เชธเชพเชฅเซ เชเซเชฌ เช เชธเชฐเชณ เชเซ. เช เชฎเซ เชซเชเซเชค เชชเซเชเซเชเชฎเชพเชเชฅเซ เชจเชฟเชฐเซเชเซเชทเช เชกเซเชเซเชฐเซเชเชฐเชจเซ เช เชเชเซ เชเชเช เชเซเช เชเชเช เชชเชฐ, เช เชจเซ เชฐเซเชจเซเชกเชฐ เชเชชเซเชเชช เชเซเชฒ เชเชฐเชตเชพเชฎเชพเช เชเชตเชถเซ เชเซเชฏเชพเชฐเซ เชเชเช เชซเซเชฐเชซเชพเชฐ เชฆเซเชตเชพเชฐเชพ เชธเชเชฆเชฐเซเชญเชฟเชค เชเซเชเชชเชฃ เช เชตเชฒเซเชเชจเชเซเชทเชฎ. เชคเชฎเชพเชฐเซ เชเซเช เชฎเซเชชเชธเซเชเซเชเชเซเชชเซเชฐเซเชชเซเชธเชจเซ เชเชฐเซเชฐ เชจเชฅเซ เช เชฅเชตเชพ เชฐเซเชกเชเซเชธเชจเซ เชเซเชฎ เชเชจเซเชเซเช เชเชฐเชตเชพเชจเซ เชเชฐเซเชฐ เชจเชฅเซ. เชฌเชงเซเช เช เชฌเซเชเซเชธเชจเซ เชฌเชนเชพเชฐ เชเชพเชฎ เชเชฐเซ เชเซ:
import React, {Component, Fragment} from 'react'
import {observer} from "mobx-react";
import Init from './components/Initialize'
import Keys from './components/Keys'
import Sign from './components/Sign'
import Unlock from './components/Unlock'
@observer // ะฃ ะะพะผะฟะพะฝะตัะฐ ั ััะธะผ ะดะตะบะพัะฐัะพะผ ะฑัะดะตั ะฐะฒัะพะผะฐัะธัะตัะบะธ ะฒัะทะฒะฐะฝ ะผะตัะพะด render, ะตัะปะธ ะฑัะดัั ะธะทะผะตะฝะตะฝั observable ะฝะฐ ะบะพัะพััะต ะพะฝ ัััะปะฐะตััั
export default class App extends Component {
// ะัะฐะฒะธะปัะฝะพ ะบะพะฝะตัะฝะพ ะฒัะฝะตััะธ ะปะพะณะธะบั ัะตะฝะดะตัะฐ ัััะฐะฝะธั ะฒ ัะพััะธะฝะณ ะธ ะฝะต ะธัะฟะพะปัะทะพะฒะฐัั ะฒะปะพะถะตะฝะฝัะต ัะตัะฝะฐัะฝัะต ะพะฟะตัะฐัะพัั,
// ะธ ะฟัะธะฒัะทัะฒะฐัั observable ะธ ะผะตัะพะดั background ะฝะตะฟะพััะตะดััะฒะตะฝะฝะพ ะบ ัะตะผ ะบะพะผะฟะพะฝะตะฝัะฐะผ, ะบะพัะพััะต ะธั
ะธัะฟะพะปัะทััั
render() {
const {keys, messages, initialized, locked} = this.props.background.state;
const {lock, unlock, addKey, removeKey, initVault, deleteVault, approve, reject} = this.props.background;
return <Fragment>
{!initialized
?
<Init onInit={initVault}/>
:
locked
?
<Unlock onUnlock={unlock}/>
:
messages.length > 0
?
<Sign keys={keys} message={messages[messages.length - 1]} onApprove={approve} onReject={reject}/>
:
<Keys keys={keys} onAdd={addKey} onRemove={removeKey}/>
}
<div>
{!locked && <button onClick={() => lock()}>Lock App</button>}
{initialized && <button onClick={() => deleteVault()}>Delete all keys and init</button>}
</div>
</Fragment>
}
}เชฌเชพเชเซเชจเชพ เชเชเชเซ เชเซเชกเชฎเชพเช เชเซเช เชถเชเชพเชฏ เชเซ .
เชนเชตเซ เชเชชเซเชฒเซเชเซเชถเชจ เชเซเชฒเชพเชธเชฎเชพเช เชคเชฎเชพเชฐเซ UI เชฎเชพเชเซ เชธเซเชเซเช เชธเชฟเชฒเซเชเซเชเชฐ เชฌเชจเชพเชตเชตเชพเชจเซ เชเชฐเซเชฐ เชเซ เช
เชจเซ เชเซเชฏเชพเชฐเซ UI เชฌเชฆเชฒเชพเชฏ เชคเซเชฏเชพเชฐเซ เชคเซเชจเซ เชธเซเชเชฟเชค เชเชฐเชตเซเช เชชเชกเชถเซ. เช เชเชฐเชตเชพ เชฎเชพเชเซ, เชเชพเชฒเซ เชเช เชชเชฆเซเชงเชคเชฟ เชเชฎเซเชฐเซเช getState ะธ reactionเชเซเชฒเชฟเชเช remote.updateState:
import {action, observable, reaction} from 'mobx';
import uuid from 'uuid/v4';
import {signTx} from '@waves/waves-transactions'
import {setupDnode} from "./utils/setupDnode";
import {decrypt, encrypt} from "./utils/cryptoUtils";
export class SignerApp {
...
// public
getState() {
return {
keys: this.store.keys,
messages: this.store.newMessages,
initialized: this.store.initialized,
locked: this.store.locked
}
}
...
//
connectPopup(connectionStream) {
const api = this.popupApi();
const dnode = setupDnode(connectionStream, api);
dnode.once('remote', (remote) => {
// ะกะพะทะดะฐะตะผ reaction ะฝะฐ ะธะทะผะตะฝะตะฝะธั ััะตะนัะฐ, ะบะพัะพััะน ัะดะตะปะฐะตั ะฒัะทะพะฒะตั ัะดะฐะปะตะฝะฝั ะฟัะพัะตะดััั ะธ ะพะฑะฝะพะฒะธั ััะตะนั ะฒ ui ะฟัะพัะตััะต
const updateStateReaction = reaction(
() => this.getState(),
(state) => remote.updateState(state),
// ะขัะตััะธะผ ะฐัะณัะผะตะฝัะพะผ ะผะพะถะฝะพ ะฟะตัะตะดะฐะฒะฐัั ะฟะฐัะฐะผะตััั. fireImmediatly ะทะฝะฐัะธั ััะพ reaction ะฒัะฟะพะปะฝะธัััั ะฟะตัะฒัะน ัะฐะท ััะฐะทั.
// ะญัะพ ะฝะตะพะฑั
ะพะดะธะผะพ, ััะพะฑั ะฟะพะปััะธัั ะฝะฐัะฐะปัะฝะพะต ัะพััะพัะฝะธะต. Delay ะฟะพะทะฒะพะปัะตั ัััะฐะฝะพะฒะธัั debounce
{fireImmediately: true, delay: 500}
);
// ะฃะดะฐะปะธะผ ะฟะพะดะฟะธัะบั ะฟัะธ ะพัะบะปััะตะฝะธะธ ะบะปะธะตะฝัะฐ
dnode.once('end', () => updateStateReaction.dispose())
})
}
...
}เชเชฌเซเชเซเชเซเช เชชเซเชฐเชพเชชเซเชค เชเชฐเชคเซ เชตเชเชคเซ remote เชฌเชจเชพเชตเชตเชพเชฎเชพเช เชเชตเซ เชฐเชนเซ เชเซ reaction UI เชฌเชพเชเซ เชชเชฐ เชซเชเชเซเชถเชจเชจเซ เชเซเชฒ เชเชฐเชคเซ เชธเซเชฅเชฟเชคเชฟเชจเซ เชฌเชฆเชฒเชตเชพ เชฎเชพเชเซ.
เช เชเชคเชฟเชฎ เชธเซเชชเชฐเซเชถ เช เชเชเซเชธเซเชเซเชเชถเชจ เชเชฏเชเชจ เชชเชฐ เชจเชตเชพ เชธเชเชฆเซเชถเชพเชเชจเซเช เชชเซเชฐเชฆเชฐเซเชถเชจ เชเชฎเซเชฐเชตเชพเชจเซเช เชเซ:
function setupApp() {
...
// Reaction ะฝะฐ ะฒัััะฐะฒะปะตะฝะธะต ัะตะบััะฐ ะฑะตะดะถะฐ.
reaction(
() => app.store.newMessages.length > 0 ? app.store.newMessages.length.toString() : '',
text => extensionApi.browserAction.setBadgeText({text}),
{fireImmediately: true}
);
...
}เชคเซเชฅเซ, เชเชชเซเชฒเชฟเชเซเชถเชจ เชคเซเชฏเชพเชฐ เชเซ. เชตเซเชฌ เชชเซเชทเซเช เซ เชตเซเชฏเชตเชนเชพเชฐเซ เชฎเชพเชเซ เชธเชนเซ เชฎเชพเชเซ เชตเชฟเชจเชเชคเซ เชเชฐเซ เชถเชเซ เชเซ:


เชเซเชก เช เชนเซเช เชเชชเชฒเชฌเซเชง เชเซ .
เชจเชฟเชทเซเชเชฐเซเชท
เชเซ เชคเชฎเซ เชฒเซเชเชจเซ เช เชเชค เชธเซเชงเซ เชตเชพเชเชเซเชฏเซ เชนเซเชฏ, เชชเชฐเชเชคเซ เชนเชเซ เชชเชฃ เชชเซเชฐเชถเซเชจเซ เชนเซเชฏ, เชคเซ เชคเชฎเซ เชคเซเชฎเชจเซ เช เชนเซเช เชชเซเชเซ เชถเชเซ เชเซ . เชคเซเชฏเชพเช เชคเชฎเชจเซ เชฆเชฐเซเช เชจเชฟเชฏเซเชเซเชค เชชเชเชฒเชพ เชฎเชพเชเซ เชเชฎเชฟเช เชชเชฃ เชฎเชณเชถเซ.
เช เชจเซ เชเซ เชคเชฎเชจเซ เชตเชพเชธเซเชคเชตเชฟเช เชเชเซเชธเซเชเซเชเชถเชจ เชฎเชพเชเซ เชเซเชก เชเซเชตเชพเชฎเชพเช เชฐเชธ เชนเซเชฏ, เชคเซ เชคเชฎเซ เช เชถเซเชงเซ เชถเชเซ เชเซ .
เชคเชฐเชซเชฅเซ เชเซเชก, เชฐเซเชชเซเชเซเชเชฐเซ เช เชจเซ เชเซเชฌ เชตเชฐเซเชฃเชจ
เชธเซเชฐเซเชธ: www.habr.com
