diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -8,7 +8,7 @@ return array( 'names' => array( 'core.pkg.css' => '63e782fb', - 'core.pkg.js' => '44aac665', + 'core.pkg.js' => '408edfa5', 'darkconsole.pkg.js' => '8ab24e01', 'differential.pkg.css' => '8af45893', 'differential.pkg.js' => 'dad3622f', @@ -166,7 +166,7 @@ 'rsrc/externals/javelin/core/__tests__/install.js' => 'c432ee85', 'rsrc/externals/javelin/core/__tests__/stratcom.js' => 'da194d4b', 'rsrc/externals/javelin/core/__tests__/util.js' => 'd3b157a9', - 'rsrc/externals/javelin/core/init.js' => 'b88ab49e', + 'rsrc/externals/javelin/core/init.js' => 'b5b4929d', 'rsrc/externals/javelin/core/init_node.js' => 'd7dde471', 'rsrc/externals/javelin/core/install.js' => '1ffb3a9c', 'rsrc/externals/javelin/core/util.js' => '90e3fde9', @@ -193,6 +193,7 @@ 'rsrc/externals/javelin/lib/DOM.js' => 'c4569c05', 'rsrc/externals/javelin/lib/History.js' => 'c60f4327', 'rsrc/externals/javelin/lib/JSON.js' => '69adf288', + 'rsrc/externals/javelin/lib/Leader.js' => '584afdb8', 'rsrc/externals/javelin/lib/Mask.js' => '8a41885b', 'rsrc/externals/javelin/lib/Request.js' => '97258e55', 'rsrc/externals/javelin/lib/Resource.js' => '0f81f8df', @@ -341,7 +342,7 @@ 'rsrc/image/texture/table_header_hover.png' => '038ec3b9', 'rsrc/image/texture/table_header_tall.png' => 'd56b434f', 'rsrc/js/application/aphlict/Aphlict.js' => '4a07e8e3', - 'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'f6bc26f0', + 'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => '4d27f9e3', 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'a826c925', 'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '58f7803f', 'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18', @@ -536,7 +537,7 @@ 'inline-comment-summary-css' => '8cfd34e8', 'javelin-aphlict' => '4a07e8e3', 'javelin-behavior' => '61cbc29a', - 'javelin-behavior-aphlict-dropdown' => 'f6bc26f0', + 'javelin-behavior-aphlict-dropdown' => '4d27f9e3', 'javelin-behavior-aphlict-listen' => 'a826c925', 'javelin-behavior-aphlict-status' => '58f7803f', 'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884', @@ -658,7 +659,8 @@ 'javelin-history' => 'c60f4327', 'javelin-install' => '1ffb3a9c', 'javelin-json' => '69adf288', - 'javelin-magical-init' => 'b88ab49e', + 'javelin-leader' => '584afdb8', + 'javelin-magical-init' => 'b5b4929d', 'javelin-mask' => '8a41885b', 'javelin-reactor' => '77b1cf6f', 'javelin-reactor-dom' => 'b6d401d6', @@ -1100,6 +1102,17 @@ 'javelin-install', 'javelin-util', ), + '4d27f9e3' => array( + 'javelin-behavior', + 'javelin-request', + 'javelin-stratcom', + 'javelin-vector', + 'javelin-dom', + 'javelin-uri', + 'javelin-behavior-device', + 'phabricator-title', + 'javelin-leader', + ), '4d94d9c3' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1150,6 +1163,9 @@ 'javelin-vector', 'javelin-dom', ), + '584afdb8' => array( + 'javelin-install', + ), '58f7803f' => array( 'javelin-behavior', 'javelin-aphlict', @@ -1885,16 +1901,6 @@ 'javelin-util', 'javelin-reactor', ), - 'f6bc26f0' => array( - 'javelin-behavior', - 'javelin-request', - 'javelin-stratcom', - 'javelin-vector', - 'javelin-dom', - 'javelin-uri', - 'javelin-behavior-device', - 'phabricator-title', - ), 'f7379f45' => array( 'javelin-behavior', 'javelin-dom', diff --git a/webroot/rsrc/externals/javelin/lib/Leader.js b/webroot/rsrc/externals/javelin/lib/Leader.js new file mode 100644 --- /dev/null +++ b/webroot/rsrc/externals/javelin/lib/Leader.js @@ -0,0 +1,72 @@ +/** + * @requires javelin-install + * @provides javelin-leader + * @javelin + */ + +JX.install('Leader', { + statics: { + _interval: null, + _key: 'JX.Leader.id', + + call: function(callback) { + if (!window.localStorage) { + callback(); + return; + } + + var self = JX.Leader; + if (!self._id) { + self._id = 1 + parseInt(Math.random() * 1000000000, 10); + JX.Stratcom.listen('pagehide', null, self._pagehide); + } + + + var lease = self._read(); + + // If the lease is good, we're all set. + var now = +new Date(); + if (lease.until > now) { + if (lease.id === self._id) { + if (!self._interval && lease.until > now + 10000) { + self._interval = window.setInterval(self._write, 5000); + } + + callback(); + } + return; + } + + self._write(); + + window.setTimeout(JX.bind(null, self.call, callback), 10); + }, + + _write: function() { + var self = JX.Leader; + + var str = [self._id, ((+new Date()) + 16000)].join(':'); + window.localStorage.setItem(self._key, str); + }, + + _read: function() { + var self = JX.Leader; + + leader = window.localStorage.getItem(self._key) || '0:0'; + leader = leader.split(':'); + + return { + id: parseInt(leader[0], 10), + until: parseInt(leader[1], 10) + }; + }, + + _pagehide: function() { + var self = JX.Leader; + if (self._read().id === self._id) { + window.localStorage.removeItem(self._key); + } + } + } +}); + diff --git a/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js b/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js --- a/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js +++ b/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js @@ -8,6 +8,7 @@ * javelin-uri * javelin-behavior-device * phabricator-title + * javelin-leader */ JX.behavior('aphlict-dropdown', function(config, statics) {