<commit_before>/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008, StatusNet, Inc.
 *
 * Add a notice encoded as JSON into the current timeline
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Plugin
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

// TODO: i18n

RealtimeUpdate = {
     _userid: 0,
     _replyurl: '',
     _favorurl: '',
     _deleteurl: '',
     _updatecounter: 0,

     init: function(userid, replyurl, favorurl, deleteurl)
     {
        RealtimeUpdate._userid = userid;
        RealtimeUpdate._replyurl = replyurl;
        RealtimeUpdate._favorurl = favorurl;
        RealtimeUpdate._deleteurl = deleteurl;

        DT = document.title;

        $(window).blur(function() {
          $('#notices_primary .notice').removeClass('mark-top');

          $('#notices_primary .notice:first').addClass('mark-top');

          RealtimeUpdate._updatecounter = 0;
          document.title = DT;

          return false;
        });
     },

     receive: function(data)
     {
          setTimeout(function() {
              id = data.id;

              // Don't add it if it already exists
              if ($("#notice-"+id).length > 0) {
                   return;
              }

              var noticeItem = RealtimeUpdate.makeNoticeItem(data);
              $("#notices_primary .notices").prepend(noticeItem);
              $("#notices_primary .notice:first").css({display:"none"});
              $("#notices_primary .notice:first").fadeIn(1000);
              SN.U.NoticeReply();

              RealtimeUpdate._updatecounter += 1;
              document.title = '('+RealtimeUpdate._updatecounter+') ' + DT;
          }, 500);
     },

     makeNoticeItem: function(data)
     {
          user = data['user'];
          html = data['html'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
          source = data['source'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');

          ni = "
"+
               "
"+
               ""+
               ""+
               ""+
               ""+user['screen_name']+""+
               ""+
               ""+
               "
"+html+"
"+
               "
"+
               "
"+
               ""+
               "a few seconds ago"+
               " "+
               ""+
               "from "+
                ""+source+""+ // may have a link
               "";
          if (data['in_reply_to_status_id']) {
               ni = ni+" in context";
          }

          ni = ni+"
"+
            "
";

          if (RealtimeUpdate._userid != 0) {
               var input = $("form#form_notice fieldset input#token");
               var session_key = input.val();
               ni = ni+RealtimeUpdate.makeFavoriteForm(data['id'], session_key);
               ni = ni+RealtimeUpdate.makeReplyLink(data['id'], data['user']['screen_name']);
               if (RealtimeUpdate._userid == data['user']['id']) {
                    ni = ni+RealtimeUpdate.makeDeleteLink(data['id']);
               }
          }

          ni = ni+"
"+
               "
";
          return ni;
     },

     makeFavoriteForm: function(id, session_key)
     {
          var ff;

          ff = "<form id=\"favor-"+id+"\" class=\"form_favor\" method=\"post\" action=\""+RealtimeUpdate._favorurl+"\">"+
                "<fieldset>"+
               "<legend>Favor this notice</legend>"+
               "<input name=\"token-"+id+"\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+
               "<input name=\"notice\" type=\"hidden\" id=\"notice-n"+id+"\" value=\""+id+"\"/>"+
               "<input type=\"submit\" id=\"favor-submit-"+id+"\" name=\"favor-submit-"+id+"\" class=\"submit\" value=\"Favor\" title=\"Favor this notice\"/>"+
                "</fieldset>"+
               "</form>";
          return ff;
     },

     makeReplyLink: function(id, nickname)
     {
          var rl;
          rl = "Reply "+id+"";
          return rl;
        },

     makeDeleteLink: function(id)
     {
          var dl, delurl;
          delurl = RealtimeUpdate._deleteurl.replace("0000000000", id);

          dl = "Delete";

          return dl;
     },

     addPopup: function(url, timeline, iconurl)
     {
         var NP = $('#notices_primary');
         NP.css({'position':'relative'});
         NP.prepend('<button id="realtime_timeline" title="Pop up in a window">Pop up</button>');

         var RT = $('#realtime_timeline');
         RT.css({
             'margin':'0 0 11px 0',
             'background':'transparent url('+ iconurl + ') no-repeat 0 30%',
             'padding':'0 0 0 20px',
             'display':'block',
             'position':'absolute',
             'top':'-20px',
             'right':'0',
             'border':'none',
             'cursor':'pointer',
             'color':$('a').css('color'),
             'font-weight':'bold',
             'font-size':'1em'
         });
         $('#showstream #notices_primary').css({'margin-top':'18px'});

         RT.click(function() {
             window.open(url,
                         timeline,
                         'toolbar=no,resizable=yes,scrollbars=yes,status=yes,width=500,height=550');

             return false;
         });
     },

     initPopupWindow: function()
     {
         $('address').hide();
         $('#content').css({'width':'93.5%'});

         $('#form_notice').css({
            'margin':'18px 0 18px 1.795%',
            'width':'93%',
            'max-width':'451px'
         });

         $('#form_notice label[for=notice_data-text], h1').css({'display': 'none'});

         $('.notices li:first-child').css({'border-top-color':'transparent'});

         $('#form_notice label[for="notice_data-attach"], #form_notice #notice_data-attach').css({'top':'0'});

         $('#form_notice #notice_data-attach').css({
            'left':'auto',
            'right':'0'
         });
     }
}

<commit_msg>Added on click event to open up anchors in notice items in a new window for the Realtime plugin's pop-up window.<commit_after>/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008, StatusNet, Inc.
 *
 * Add a notice encoded as JSON into the current timeline
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Plugin
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

// TODO: i18n

RealtimeUpdate = {
     _userid: 0,
     _replyurl: '',
     _favorurl: '',
     _deleteurl: '',
     _updatecounter: 0,

     init: function(userid, replyurl, favorurl, deleteurl)
     {
        RealtimeUpdate._userid = userid;
        RealtimeUpdate._replyurl = replyurl;
        RealtimeUpdate._favorurl = favorurl;
        RealtimeUpdate._deleteurl = deleteurl;

        DT = document.title;

        $(window).blur(function() {
          $('#notices_primary .notice').removeClass('mark-top');

          $('#notices_primary .notice:first').addClass('mark-top');

          RealtimeUpdate._updatecounter = 0;
          document.title = DT;

          return false;
        });
     },

     receive: function(data)
     {
          setTimeout(function() {
              id = data.id;

              // Don't add it if it already exists
              if ($("#notice-"+id).length > 0) {
                   return;
              }

              var noticeItem = RealtimeUpdate.makeNoticeItem(data);
              $("#notices_primary .notices").prepend(noticeItem);
              $("#notices_primary .notice:first").css({display:"none"});
              $("#notices_primary .notice:first").fadeIn(1000);
              SN.U.NoticeReply();

              RealtimeUpdate._updatecounter += 1;
              document.title = '('+RealtimeUpdate._updatecounter+') ' + DT;
          }, 500);
     },

     makeNoticeItem: function(data)
     {
          user = data['user'];
          html = data['html'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
          source = data['source'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');

          ni = "
"+
               "
"+
               ""+
               ""+
               ""+
               ""+user['screen_name']+""+
               ""+
               ""+
               "
"+html+"
"+
               "
"+
               "
"+
               ""+
               "a few seconds ago"+
               " "+
               ""+
               "from "+
                ""+source+""+ // may have a link
               "";
          if (data['in_reply_to_status_id']) {
               ni = ni+" in context";
          }

          ni = ni+"
"+
            "
";

          if (RealtimeUpdate._userid != 0) {
               var input = $("form#form_notice fieldset input#token");
               var session_key = input.val();
               ni = ni+RealtimeUpdate.makeFavoriteForm(data['id'], session_key);
               ni = ni+RealtimeUpdate.makeReplyLink(data['id'], data['user']['screen_name']);
               if (RealtimeUpdate._userid == data['user']['id']) {
                    ni = ni+RealtimeUpdate.makeDeleteLink(data['id']);
               }
          }

          ni = ni+"
"+
               "
";
          return ni;
     },

     makeFavoriteForm: function(id, session_key)
     {
          var ff;

          ff = "<form id=\"favor-"+id+"\" class=\"form_favor\" method=\"post\" action=\""+RealtimeUpdate._favorurl+"\">"+
                "<fieldset>"+
               "<legend>Favor this notice</legend>"+
               "<input name=\"token-"+id+"\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+
               "<input name=\"notice\" type=\"hidden\" id=\"notice-n"+id+"\" value=\""+id+"\"/>"+
               "<input type=\"submit\" id=\"favor-submit-"+id+"\" name=\"favor-submit-"+id+"\" class=\"submit\" value=\"Favor\" title=\"Favor this notice\"/>"+
                "</fieldset>"+
               "</form>";
          return ff;
     },

     makeReplyLink: function(id, nickname)
     {
          var rl;
          rl = "Reply "+id+"";
          return rl;
        },

     makeDeleteLink: function(id)
     {
          var dl, delurl;
          delurl = RealtimeUpdate._deleteurl.replace("0000000000", id);

          dl = "Delete";

          return dl;
     },

     addPopup: function(url, timeline, iconurl)
     {
         var NP = $('#notices_primary');
         NP.css({'position':'relative'});
         NP.prepend('<button id="realtime_timeline" title="Pop up in a window">Pop up</button>');

         var RT = $('#realtime_timeline');
         RT.css({
             'margin':'0 0 11px 0',
             'background':'transparent url('+ iconurl + ') no-repeat 0 30%',
             'padding':'0 0 0 20px',
             'display':'block',
             'position':'absolute',
             'top':'-20px',
             'right':'0',
             'border':'none',
             'cursor':'pointer',
             'color':$('a').css('color'),
             'font-weight':'bold',
             'font-size':'1em'
         });
         $('#showstream #notices_primary').css({'margin-top':'18px'});

         RT.click(function() {
             window.open(url,
                         timeline,
                         'toolbar=no,resizable=yes,scrollbars=yes,status=yes,width=500,height=550');

             return false;
         });
     },

     initPopupWindow: function()
     {
         $('address').hide();
         $('#content').css({'width':'93.5%'});

         $('#form_notice').css({
            'margin':'18px 0 18px 1.795%',
            'width':'93%',
            'max-width':'451px'
         });

         $('#form_notice label[for=notice_data-text], h1').css({'display': 'none'});

         $('.notices li:first-child').css({'border-top-color':'transparent'});

         $('#form_notice label[for="notice_data-attach"], #form_notice #notice_data-attach').css({'top':'0'});

         $('#form_notice #notice_data-attach').css({
            'left':'auto',
            'right':'0'
         });

         $('.notices .entry-title a, .notices .entry-content a').bind('click', function() {
            window.open(this.href, '');

            return false;
         });
     }
}

<|endoftext|>


<commit_before>/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008, StatusNet, Inc.
 *
 * Add a notice encoded as JSON into the current timeline
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Plugin
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

// TODO: i18n

RealtimeUpdate = {
     _userid: 0,
     _replyurl: '',
     _favorurl: '',
     _repeaturl: '',
     _deleteurl: '',
     _updatecounter: 0,
     _maxnotices: 50,
     _windowhasfocus: true,
     _documenttitle: '',
     _paused:false,
     _queuedNotices:[],

     init: function(userid, replyurl, favorurl, repeaturl, deleteurl)
     {
        RealtimeUpdate._userid = userid;
        RealtimeUpdate._replyurl = replyurl;
        RealtimeUpdate._favorurl = favorurl;
        RealtimeUpdate._repeaturl = repeaturl;
        RealtimeUpdate._deleteurl = deleteurl;

        RealtimeUpdate._documenttitle = document.title;

        $(window).bind('focus', function(){ RealtimeUpdate._windowhasfocus = true; });

        $(window).bind('blur', function() {
          $('#notices_primary .notice').removeClass('mark-top');

          $('#notices_primary .notice:first').addClass('mark-top');

          RealtimeUpdate._updatecounter = 0;
          document.title = RealtimeUpdate._documenttitle;
          RealtimeUpdate._windowhasfocus = false;

          return false;
        });
     },

     receive: function(data)
     {
          if (RealtimeUpdate._paused === false) {
              RealtimeUpdate.purgeLastNoticeItem();

              RealtimeUpdate.insertNoticeItem(data);
          }
          else {
              RealtimeUpdate._queuedNotices.push(data);

              RealtimeUpdate.updateQueuedCounter();
          }

          RealtimeUpdate.updateWindowCounter();
     },

     insertNoticeItem: function(data) {
        // Don't add it if it already exists
        if ($("#notice-"+data.id).length > 0) {
            return;
        }

        var noticeItem = RealtimeUpdate.makeNoticeItem(data);
        var noticeItemID = $(noticeItem).attr('id');

        $("#notices_primary .notices").prepend(noticeItem);
        $("#notices_primary .notice:first").css({display:"none"});
        $("#notices_primary .notice:first").fadeIn(1000);

        SN.U.FormXHR($('#'+noticeItemID+' .form_favor'));
        SN.U.NoticeReplyTo($('#'+noticeItemID));
        SN.U.FormXHR($('#'+noticeItemID+' .form_repeat'));
        SN.U.NoticeWithAttachment($('#'+noticeItemID));
     },

     purgeLastNoticeItem: function() {
        if ($('#notices_primary .notice').length > RealtimeUpdate._maxnotices) {
            $("#notices_primary .notice:last").remove();
        }
     },

     updateWindowCounter: function() {
          if (RealtimeUpdate._windowhasfocus === false) {
              RealtimeUpdate._updatecounter += 1;
              document.title = '('+RealtimeUpdate._updatecounter+') ' + RealtimeUpdate._documenttitle;
          }
     },

     makeNoticeItem: function(data)
     {
          if (data.hasOwnProperty('retweeted_status')) {
               original = data['retweeted_status'];
               repeat   = data;
               data     = original;
               unique   = repeat['id'];
               responsible = repeat['user'];
          } else {
               original = null;
               repeat = null;
               unique = data['id'];
               responsible = data['user'];
          }

          user = data['user'];
          html = data['html'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
          source = data['source'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');

          ni = "
"+
               "
"+
               ""+
               ""+
               ""+
               ""+user['screen_name']+""+
               ""+
               ""+
               "
"+html+"
"+
               "
"+
               "
"+
               ""+
               "a few seconds ago"+
               " "+
               ""+
               "from "+
                ""+source+""+ // may have a link
               "";
          if (data['in_reply_to_status_id']) {
               ni = ni+" in context";
          }

          if (repeat) {
               ru = repeat['user'];
               ni = ni + "Repeated by " +
                    "" +
                    ""+ ru['screen_name'] + "";
          }

          ni = ni+"
";

          ni = ni + "
";

          if (RealtimeUpdate._userid != 0) {
               var input = $("form#form_notice fieldset input#token");
               var session_key = input.val();
               ni = ni+RealtimeUpdate.makeFavoriteForm(data['id'], session_key);
               ni = ni+RealtimeUpdate.makeReplyLink(data['id'], data['user']['screen_name']);
               if (RealtimeUpdate._userid == responsible['id']) {
                    ni = ni+RealtimeUpdate.makeDeleteLink(data['id']);
               }
               else {
                    ni = ni+RealtimeUpdate.makeRepeatForm(data['id'],  session_key);
               }
          }

          ni = ni+"
";

               "
";
          return ni;
     },

     makeFavoriteForm: function(id, session_key)
     {
          var ff;

          ff = "<form id=\"favor-"+id+"\" class=\"form_favor\" method=\"post\" action=\""+RealtimeUpdate._favorurl+"\">"+
                "<fieldset>"+
               "<legend>Favor this notice</legend>"+
               "<input name=\"token-"+id+"\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+
               "<input name=\"notice\" type=\"hidden\" id=\"notice-n"+id+"\" value=\""+id+"\"/>"+
               "<input type=\"submit\" id=\"favor-submit-"+id+"\" name=\"favor-submit-"+id+"\" class=\"submit\" value=\"Favor\" title=\"Favor this notice\"/>"+
                "</fieldset>"+
               "</form>";
          return ff;
     },

     makeReplyLink: function(id, nickname)
     {
          var rl;
          rl = "Reply "+id+"";
          return rl;
     },

     makeRepeatForm: function(id, session_key)
     {
          var rf;
          rf = "<form id=\"repeat-"+id+"\" class=\"form_repeat\" method=\"post\" action=\""+RealtimeUpdate._repeaturl+"\">"+
               "<fieldset>"+
               "<legend>Favor this notice</legend>"+
               "<input name=\"token-"+id+"\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+
               "<input name=\"notice\" type=\"hidden\" id=\"notice-n"+id+"\" value=\""+id+"\"/>"+
               "<input type=\"submit\" id=\"repeat-submit-"+id+"\" name=\"repeat-submit-"+id+"\" class=\"submit\" value=\"Favor\" title=\"Repeat this notice\"/>"+
               "</fieldset>"+
               "</form>";

          return rf;
     },

     makeDeleteLink: function(id)
     {
          var dl, delurl;
          delurl = RealtimeUpdate._deleteurl.replace("0000000000", id);

          dl = "Delete";

          return dl;
     },

     initActions: function(url, timeline, path)
     {
        $('#notices_primary').prepend('

');

        RealtimeUpdate._pluginPath = path;

        RealtimeUpdate.initPlayPause();
        RealtimeUpdate.initAddPopup(url, timeline, RealtimeUpdate._pluginPath);
     },

     initPlayPause: function()
     {
        if (typeof(localStorage) == 'undefined') {
            RealtimeUpdate.showPause();
        }
        else {
            if (localStorage.getItem('RealtimeUpdate_paused') === 'true') {
                RealtimeUpdate.showPlay();
            }
            else {
                RealtimeUpdate.showPause();
            }
        }
     },

     showPause: function()
     {
        RealtimeUpdate.setPause(false);
        RealtimeUpdate.showQueuedNotices();
        RealtimeUpdate.addNoticesHover();

        $('#realtime_playpause').remove();
        $('#realtime_actions').prepend('
<button id="realtime_pause" class="pause" title="Pause">Pause</button>
');

        $('#realtime_pause').bind('click', function() {
            RealtimeUpdate.removeNoticesHover();
            RealtimeUpdate.showPlay();
            return false;
        });
     },

     showPlay: function()
     {
        RealtimeUpdate.setPause(true);
        $('#realtime_playpause').remove();
        $('#realtime_actions').prepend('
 <button id="realtime_play" class="play" title="Play">Play</button>
');

        $('#realtime_play').bind('click', function() {
            RealtimeUpdate.showPause();
            return false;
        });
     },

     setPause: function(state)
     {
        RealtimeUpdate._paused = state;
        if (typeof(localStorage) != 'undefined') {
            localStorage.setItem('RealtimeUpdate_paused', RealtimeUpdate._paused);
        }
     },

     showQueuedNotices: function()
     {
        $.each(RealtimeUpdate._queuedNotices, function(i, n) {
            RealtimeUpdate.insertNoticeItem(n);
        });

        RealtimeUpdate._queuedNotices = [];

        RealtimeUpdate.removeQueuedCounter();
     },

     updateQueuedCounter: function()
     {
        $('#realtime_playpause #queued_counter').html('('+RealtimeUpdate._queuedNotices.length+')');
     },

     removeQueuedCounter: function()
     {
        $('#realtime_playpause #queued_counter').empty();
     },

     addNoticesHover: function()
     {
        $('#notices_primary .notices').hover(
            function() {
                if (RealtimeUpdate._paused === false) {
                    RealtimeUpdate.showPlay();
                }
            },
            function() {
                if (RealtimeUpdate._paused === true) {
                    RealtimeUpdate.showPause();
                }
            }
        );
     },

     removeNoticesHover: function()
     {
        $('#notices_primary .notices').unbind();
     },

     initAddPopup: function(url, timeline, path)
     {
         $('#realtime_timeline').append('<button id="realtime_popup" title="Pop up in a window">Pop up</button>');

         $('#realtime_popup').bind('click', function() {
             window.open(url,
                         '',
                         'toolbar=no,resizable=yes,scrollbars=yes,status=no,menubar=no,personalbar=no,location=no,width=500,height=550');

             return false;
         });
     },

     initPopupWindow: function()
     {
         $('.notices .entry-title a, .notices .entry-content a').bind('click', function() {
            window.open(this.href, '');

            return false;
         });

         $('#showstream .entity_profile').css({'width':'69%'});
     }
}

<commit_msg>can't repeat your own notice posted through realtime<commit_after>/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008, StatusNet, Inc.
 *
 * Add a notice encoded as JSON into the current timeline
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Plugin
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

// TODO: i18n

RealtimeUpdate = {
     _userid: 0,
     _replyurl: '',
     _favorurl: '',
     _repeaturl: '',
     _deleteurl: '',
     _updatecounter: 0,
     _maxnotices: 50,
     _windowhasfocus: true,
     _documenttitle: '',
     _paused:false,
     _queuedNotices:[],

     init: function(userid, replyurl, favorurl, repeaturl, deleteurl)
     {
        RealtimeUpdate._userid = userid;
        RealtimeUpdate._replyurl = replyurl;
        RealtimeUpdate._favorurl = favorurl;
        RealtimeUpdate._repeaturl = repeaturl;
        RealtimeUpdate._deleteurl = deleteurl;

        RealtimeUpdate._documenttitle = document.title;

        $(window).bind('focus', function(){ RealtimeUpdate._windowhasfocus = true; });

        $(window).bind('blur', function() {
          $('#notices_primary .notice').removeClass('mark-top');

          $('#notices_primary .notice:first').addClass('mark-top');

          RealtimeUpdate._updatecounter = 0;
          document.title = RealtimeUpdate._documenttitle;
          RealtimeUpdate._windowhasfocus = false;

          return false;
        });
     },

     receive: function(data)
     {
          if (RealtimeUpdate._paused === false) {
              RealtimeUpdate.purgeLastNoticeItem();

              RealtimeUpdate.insertNoticeItem(data);
          }
          else {
              RealtimeUpdate._queuedNotices.push(data);

              RealtimeUpdate.updateQueuedCounter();
          }

          RealtimeUpdate.updateWindowCounter();
     },

     insertNoticeItem: function(data) {
        // Don't add it if it already exists
        if ($("#notice-"+data.id).length > 0) {
            return;
        }

        var noticeItem = RealtimeUpdate.makeNoticeItem(data);
        var noticeItemID = $(noticeItem).attr('id');

        $("#notices_primary .notices").prepend(noticeItem);
        $("#notices_primary .notice:first").css({display:"none"});
        $("#notices_primary .notice:first").fadeIn(1000);

        SN.U.FormXHR($('#'+noticeItemID+' .form_favor'));
        SN.U.NoticeReplyTo($('#'+noticeItemID));
        SN.U.FormXHR($('#'+noticeItemID+' .form_repeat'));
        SN.U.NoticeWithAttachment($('#'+noticeItemID));
     },

     purgeLastNoticeItem: function() {
        if ($('#notices_primary .notice').length > RealtimeUpdate._maxnotices) {
            $("#notices_primary .notice:last").remove();
        }
     },

     updateWindowCounter: function() {
          if (RealtimeUpdate._windowhasfocus === false) {
              RealtimeUpdate._updatecounter += 1;
              document.title = '('+RealtimeUpdate._updatecounter+') ' + RealtimeUpdate._documenttitle;
          }
     },

     makeNoticeItem: function(data)
     {
          if (data.hasOwnProperty('retweeted_status')) {
               original = data['retweeted_status'];
               repeat   = data;
               data     = original;
               unique   = repeat['id'];
               responsible = repeat['user'];
          } else {
               original = null;
               repeat = null;
               unique = data['id'];
               responsible = data['user'];
          }

          user = data['user'];
          html = data['html'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
          source = data['source'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');

          ni = "
"+
               "
"+
               ""+
               ""+
               ""+
               ""+user['screen_name']+""+
               ""+
               ""+
               "
"+html+"
"+
               "
"+
               "
"+
               ""+
               "a few seconds ago"+
               " "+
               ""+
               "from "+
                ""+source+""+ // may have a link
               "";
          if (data['in_reply_to_status_id']) {
               ni = ni+" in context";
          }

          if (repeat) {
               ru = repeat['user'];
               ni = ni + "Repeated by " +
                    "" +
                    ""+ ru['screen_name'] + "";
          }

          ni = ni+"
";

          ni = ni + "
";

          if (RealtimeUpdate._userid != 0) {
               var input = $("form#form_notice fieldset input#token");
               var session_key = input.val();
               ni = ni+RealtimeUpdate.makeFavoriteForm(data['id'], session_key);
               ni = ni+RealtimeUpdate.makeReplyLink(data['id'], data['user']['screen_name']);
               if (RealtimeUpdate._userid == responsible['id']) {
                    ni = ni+RealtimeUpdate.makeDeleteLink(data['id']);
               } else if (RealtimeUpdate._userid != user['id']) {
                    ni = ni+RealtimeUpdate.makeRepeatForm(data['id'],  session_key);
               }
          }

          ni = ni+"
";

               "
";
          return ni;
     },

     makeFavoriteForm: function(id, session_key)
     {
          var ff;

          ff = "<form id=\"favor-"+id+"\" class=\"form_favor\" method=\"post\" action=\""+RealtimeUpdate._favorurl+"\">"+
                "<fieldset>"+
               "<legend>Favor this notice</legend>"+
               "<input name=\"token-"+id+"\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+
               "<input name=\"notice\" type=\"hidden\" id=\"notice-n"+id+"\" value=\""+id+"\"/>"+
               "<input type=\"submit\" id=\"favor-submit-"+id+"\" name=\"favor-submit-"+id+"\" class=\"submit\" value=\"Favor\" title=\"Favor this notice\"/>"+
                "</fieldset>"+
               "</form>";
          return ff;
     },

     makeReplyLink: function(id, nickname)
     {
          var rl;
          rl = "Reply "+id+"";
          return rl;
     },

     makeRepeatForm: function(id, session_key)
     {
          var rf;
          rf = "<form id=\"repeat-"+id+"\" class=\"form_repeat\" method=\"post\" action=\""+RealtimeUpdate._repeaturl+"\">"+
               "<fieldset>"+
               "<legend>Favor this notice</legend>"+
               "<input name=\"token-"+id+"\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+
               "<input name=\"notice\" type=\"hidden\" id=\"notice-n"+id+"\" value=\""+id+"\"/>"+
               "<input type=\"submit\" id=\"repeat-submit-"+id+"\" name=\"repeat-submit-"+id+"\" class=\"submit\" value=\"Favor\" title=\"Repeat this notice\"/>"+
               "</fieldset>"+
               "</form>";

          return rf;
     },

     makeDeleteLink: function(id)
     {
          var dl, delurl;
          delurl = RealtimeUpdate._deleteurl.replace("0000000000", id);

          dl = "Delete";

          return dl;
     },

     initActions: function(url, timeline, path)
     {
        $('#notices_primary').prepend('

');

        RealtimeUpdate._pluginPath = path;

        RealtimeUpdate.initPlayPause();
        RealtimeUpdate.initAddPopup(url, timeline, RealtimeUpdate._pluginPath);
     },

     initPlayPause: function()
     {
        if (typeof(localStorage) == 'undefined') {
            RealtimeUpdate.showPause();
        }
        else {
            if (localStorage.getItem('RealtimeUpdate_paused') === 'true') {
                RealtimeUpdate.showPlay();
            }
            else {
                RealtimeUpdate.showPause();
            }
        }
     },

     showPause: function()
     {
        RealtimeUpdate.setPause(false);
        RealtimeUpdate.showQueuedNotices();
        RealtimeUpdate.addNoticesHover();

        $('#realtime_playpause').remove();
        $('#realtime_actions').prepend('
<button id="realtime_pause" class="pause" title="Pause">Pause</button>
');

        $('#realtime_pause').bind('click', function() {
            RealtimeUpdate.removeNoticesHover();
            RealtimeUpdate.showPlay();
            return false;
        });
     },

     showPlay: function()
     {
        RealtimeUpdate.setPause(true);
        $('#realtime_playpause').remove();
        $('#realtime_actions').prepend('
 <button id="realtime_play" class="play" title="Play">Play</button>
');

        $('#realtime_play').bind('click', function() {
            RealtimeUpdate.showPause();
            return false;
        });
     },

     setPause: function(state)
     {
        RealtimeUpdate._paused = state;
        if (typeof(localStorage) != 'undefined') {
            localStorage.setItem('RealtimeUpdate_paused', RealtimeUpdate._paused);
        }
     },

     showQueuedNotices: function()
     {
        $.each(RealtimeUpdate._queuedNotices, function(i, n) {
            RealtimeUpdate.insertNoticeItem(n);
        });

        RealtimeUpdate._queuedNotices = [];

        RealtimeUpdate.removeQueuedCounter();
     },

     updateQueuedCounter: function()
     {
        $('#realtime_playpause #queued_counter').html('('+RealtimeUpdate._queuedNotices.length+')');
     },

     removeQueuedCounter: function()
     {
        $('#realtime_playpause #queued_counter').empty();
     },

     addNoticesHover: function()
     {
        $('#notices_primary .notices').hover(
            function() {
                if (RealtimeUpdate._paused === false) {
                    RealtimeUpdate.showPlay();
                }
            },
            function() {
                if (RealtimeUpdate._paused === true) {
                    RealtimeUpdate.showPause();
                }
            }
        );
     },

     removeNoticesHover: function()
     {
        $('#notices_primary .notices').unbind();
     },

     initAddPopup: function(url, timeline, path)
     {
         $('#realtime_timeline').append('<button id="realtime_popup" title="Pop up in a window">Pop up</button>');

         $('#realtime_popup').bind('click', function() {
             window.open(url,
                         '',
                         'toolbar=no,resizable=yes,scrollbars=yes,status=no,menubar=no,personalbar=no,location=no,width=500,height=550');

             return false;
         });
     },

     initPopupWindow: function()
     {
         $('.notices .entry-title a, .notices .entry-content a').bind('click', function() {
            window.open(this.href, '');

            return false;
         });

         $('#showstream .entity_profile').css({'width':'69%'});
     }
}

<|endoftext|>


<commit_before>define(function(require, exports, module) {
    main.consumes = [
        "c9", "Plugin", "fs", "settings", "tabManager", "dialog.error",
        "dialog.question", "preferences", "save"
    ];
    main.provides = ["metadata"];
    return main;

    function main(options, imports, register) {
        var c9 = imports.c9;
        var Plugin = imports.Plugin;
        var fs = imports.fs;
        var settings = imports.settings;
        var save = imports.save;
        var tabs = imports.tabManager;
        var confirm = imports["dialog.question"].show;
        var showError = imports["dialog.error"].show;
        var prefs = imports.preferences;

        /***** Initialization *****/

        var plugin = new Plugin("Ajax.org", main.consumes);
        var emit = plugin.getEmitter();

        var PATH = options.path || "/.c9/metadata";
        var WORKSPACE = "/workspace";

        var jobs = {};
        var changed = {};
        var cached = {};
        var worker, timer;

        var CHANGE_CHECK_INTERVAL = options.changeCheckInterval || 30000;

        var loaded = false;
        function load(){
            if (loaded) return false;
            loaded = true;

            // Schedule for inspection when tab becomes active
            tabs.on("tabAfterActivate", function(e) {
                // If disabled don't do anything
                if (!e.tab.loaded || !settings.getBool("user/metadata/@enabled"))
                    return;

                if (e.lastTab)
                    changed[e.lastTab.name] = e.lastTab;

                changed[e.tab.name] = e.tab;
            }, plugin);

            // Closing a tab
            tabs.on("tabAfterClose", function (e) {
                // If disabled don't do anything
                if (!settings.getBool("user/metadata/@enabled"))
                    return;

                var doc = e.tab.document;
                if (!e.tab.path) {
                    fs.unlink(PATH + "/" + e.tab.name, function(){ return false });
                }
                else if (doc.meta.newfile || doc.meta.$ignoreSave) {
                    fs.unlink(PATH + WORKSPACE + e.tab.path, function(){ return false });
                }
                else if (check(e.tab) !== false) {
                    delete changed[e.tab.name];
                    delete cached[e.tab.name];
                }
            }, plugin);

            // Opening a file
            tabs.on("beforeOpen", function(e) {
                // If disabled don't do anything
                if (!settings.getBool("user/metadata/@enabled"))
                    return;

                // Don't load metadata if document state is defined or value is set
                if (e.tab.path && e.options.document.filter === false
                  || !e.tab.path && !e.options.document.filter
                  || e.options.value)
                    return;

                // todo should tabmanager check this?
                e.options.loadFromDisk = e.loadFromDisk
                    && !e.tab.document.meta.newfile
                    && !e.tab.document.meta.nofs;

                // Fetch the metadata and real data
                var callback = function(err) {
                    if (e.loadFromDisk)
                        e.callback(err);
                };
                loadMetadata(e.tab, e.options, callback, e.options.init);

                return e.loadFromDisk ? false : true;
            }, plugin);

            // Check every half a minute for changed tabs
            timer = setInterval(function(){
                checkChangedTabs();
            }, CHANGE_CHECK_INTERVAL);

            // Delete metadata when file is renamed
            save.on("saveAs", function(e){
                if (e.path != e.oldPath)
                    fs.unlink(PATH + WORKSPACE + e.oldPath, function(){ return false });
            });

            // Settings

            settings.on("read", function(e) {
                settings.setDefaults("user/metadata", [
                    ["enabled", "true"],
                    ["undolimit", "100"],
                ]);
            }, plugin);

            settings.on("write", function(e) {
                if (e.unload) return;

                checkChangedTabs();
            }, plugin);

            function checkChangedTabs(unload) {
                // If disabled don't do anything
                if (!settings.getBool("user/metadata/@enabled"))
                    return;

                tabs.getPanes().forEach(function(pane) {
                    var tab = pane.getTab();
                    if (tab) {
                        changed[tab.name] = tab;
                    }
                });

                for (var name in changed) {
                    if (check(changed[name], unload) === false)
                        return;
                }

                changed = {};
            }

            // Preferences

            prefs.add({
                "File" : {
                    position: 150,
                    "Meta Data" : {
                        position: 200,
                        "Store Meta Data of Opened Files" : {
                            type: "checkbox",
                            path: "user/metadata/@enabled",
                            position: 100
                        },
                        "Maximum of Undo Stack Items in Meta Data" : {
                            type: "spinner",
                            path: "user/metadata/@undolimit",
                            position: 200,
                            min: 10,
                            max: 10000
                        }
                    }
                }
            }, plugin);

            // Exiting Cloud9
            c9.on("beforequit", function(){
                checkChangedTabs(true);
            }, plugin);

            // Initial Load
            tabs.getTabs().forEach(function(tab) {
                var options = tab.getState();
                options.loadFromDisk = tab.path
                  && !tab.document.meta.newfile
                  && !tab.document.meta.nofs
                  // autoload to false prevents loading data, used by image editor
                  && (!tab.editor || tab.editor.autoload !== false);

                loadMetadata(tab, options, function(err) {
                    if (err) {
                        tab.unload();
                        showError("File not found '" + tab.path + "'");
                        return;
                    }
                    tab.classList.remove("loading");
                }, true);
            });
        }

        /***** Methods *****/

        function check(tab, forceSync) {
            var docChanged = tab.document.changed || tab.document.meta.nofs;

            // Don't save state if we're offline
            if (!c9.has(c9.STORAGE))
                return false;

            if (tab.meta.$loadingMetadata)
                return;

            // Ignore metadata files and preview pages and debug files and
            // tabs that are not loaded
            if (!tab.loaded
              || tab.path && tab.path.indexOf(PATH) === 0
              || tab.document.meta.preview)
                return;

            var state = tab.document.getState();

            // Make sure timestamp is preserved
            if (state.meta)
                state.timestamp = state.meta.timestamp;

            // meta is recorded by the tab state
            delete state.meta;

            // If we discarded the file before closing, clear that data
            if (tab.document.meta.$ignoreSave) {
                delete state.value;
                delete state.changed;
                delete state.undoManager;
                docChanged = true;
            }

            if (docChanged || typeof state.value == "undefined" || forceSync) {
                if (forceSync && !docChanged && state.undoManager.stack.length)
                    delete state.value;

                write(forceSync);
            }
            else {
                hash(state.value, function(err, hash) {
                    if (err) return;

                    delete state.value;
                    delete state.changed;
                    state.hash = hash;
                    write(forceSync);
                });
            }

            function write(forceSync) {
                if (c9.readonly) return;

                var limit = settings.getNumber("user/metadata/@undolimit");
                var undo = state.undoManager;
                if (undo) {
                    var start = Math.max(0, undo.position - limit);
                    undo.stack.splice(0, start);
                    undo.position -= start;
                    undo.mark     -= start;
                }

                try {
                    // This throws when a structure is circular
                    var sstate = JSON.stringify(state);
                } catch (e) {
                    // debugger;
                    return;
                }

                // Lets not save large metadata
                if (sstate.length > 1024 * 1024) {
                    sstate = "";
                    state = {};
                }

                if (cached[tab.name] != sstate) {
                    cached[tab.name] = sstate;

                    if (tab.path) {
                        var path = (tab.path.charAt(0) == "~" ? "/" : "") + tab.path;
                        fs.metadata(path, state, forceSync, function(err) {
                            if (err)
                                return;
                        });
                    }
                    else {
                        fs.metadata("/_/_/" + tab.name, state, forceSync, function(err) {
                            if (err)
                                return;
                        });
                    }
                }
            }

            return true;
        }

        function merge(from, to) {
            for (var prop in from) {
                if (to[prop] && typeof from[prop] == "object")
                    merge(from[prop], to[prop]);
                else
                    to[prop] = from[prop];
            }
        }

        function loadMetadata(tab, options, callback, init) {
            // // When something goes wrong somewhere in cloud9, this can happen
            // if (tab.path && "/~".indexOf(tab.path.charAt(0)) == -1)
            //     debugger;

            var path = tab.path
                ? PATH + WORKSPACE + (tab.path.charAt(0) == "~" ? "/" : "") + tab.path
                : PATH + "/" + tab.name;

            var storedValue, storedMetadata;
            var xhr;

            // Prevent Saving of Metadata
            tab.meta.$loadingMetadata = true;

            // Progress Handling
            tab.classList.add("loading");

            var loadStartT = Date.now();

            // Handler to show loading indicator
            function progress(loaded, total, complete) {
                var data = {
                    total: total,
                    loaded: loaded,
                    complete: complete,
                    dt: Date.now() - loadStartT
                };

                tab.document.progress(data);
            }

            if (tab.path) {
                if (options.loadFromDisk === false) {
                    // This is for new files and other files that will store
                    // their value in the metadata
                    receive(tab.document.value);

                    // Don't load metadata of newly created newfile tabs (runtime)
                    if (!init) {
                        receive(null, -1);
                        return;
                    }
                }
                else {
                    tab.classList.add("loading");
                    // progress(0, 1, 0);

                    var cb = function(err, data, metadata, res) {
                        if (err) return callback(err);
                        receive(data, metadata || -1);
                    };

                    xhr = emit("beforeReadFile", {
                        tab: tab,
                        path: tab.path,
                        callback: cb,
                        progress: progress
                    });

                    if (!xhr)
                        xhr = fs.readFileWithMetadata(tab.path, "utf8", cb, progress);
                }
            }

            if (!xhr) {
                xhr = fs.readFile(path, "utf8", function(err, data) {
                    receive(null, err ? -1 : data);
                }, progress);
            }

            // Cancel file opening when tab is closed
            var abort = function(){ xhr && xhr.abort(); };
            tab.on("close", abort);
            tabs.on("open", function wait(e) {
                if (e.tab == tab) {
                    tab.off("close", abort);
                    tab.off("open", wait);
                }
            }, tab);

            function receive(value, metadata) {
                var state;

                if (value !== null)
                    storedValue = value;
                if (metadata) {
                    storedMetadata = metadata;
                    if (metadata != -1) {
                        cached[tab.name]
                            = metadata.replace(/"timestamp":\d+\,?$/, "");
                    }
                }

                // Final state processing and then we're done
                var compareModified = false;
                function done(state, cleansed) {
                    // Import state from options
                    var doc = options.document;
                    if (doc instanceof Plugin)
                        doc = doc.getState();

                    delete doc.fullState;
                    delete doc.value;
                    delete doc.undoManager;

                    if (!doc.changed)
                        delete doc.changed;

                    if (cleansed) {
                        delete state.undoManager;

                        if (tab.editor && state[tab.editor.type])
                            state[tab.editor.type].cleansed = true;
                    }

                    // Preserve timestamp from metadata
                    if (!doc.meta) doc.meta = {};
                    doc.meta.timestamp = state.timestamp;
                    delete state.timestamp;

                    // Merge the two sources
                    merge(doc, state);

                    if (tab.document.hasValue())
                        delete state.value;

                    // Keep original value from disk
                    state.meta.$savedValue = storedValue;

                    var sameValue = state.value === storedValue;
                    if (options.loadFromDisk && (sameValue || compareModified)) {
                        fs.stat(tab.path, function(err, stat) {
                            if (err) return;

                            if (compareModified) {
                                // @todo this won't work well on windows, because
                                // there is a 20s period in which the mtime is
                                // the same. The solution would be to have a
                                // way to compare the saved document to the
                                // loaded document that created the state
                                if (!state.meta || state.meta.timestamp < stat.mtime) {
                                    var doc = tab.document;

                                    function checkChange(){
                                        confirm("File Changed",
                                          tab.path + " has been changed on disk.",
                                          "Would you like to reload this file?",
                                          function(){ // Yes
                                              // Set new value and clear undo state
                                              doc.setBookmarkedValue(storedValue, true);
                                              doc.meta.timestamp = stat.mtime;
                                          },
                                          function(){ // No
                                              // Set to changed
                                              doc.undoManager.bookmark(-2);
                                              doc.meta.timestamp = stat.mtime;
                                          },
                                          { merge: false, all: false }
                                        );
                                    }

                                    if (state.meta.preview) {
                                        doc.editor.on("focus", function wait(e) {
                                            if (doc.editor.activeDocument == doc) {
                                                doc.editor.off("focus", wait);
                                                checkChange();
                                            }
                                        }, doc);
                                        return;
                                    }
                                    else
                                        checkChange();
                                }
                            }
                            else {
                                tab.document.meta.timestamp = stat.mtime;
                            }
                        });
                    }

                    // Set new state
                    tab.document.setState(state);

                    // Declare done
                    delete tab.meta.$loadingMetadata;

                    callback();
                }

                if ((!tab.path || storedValue !== undefined) && storedMetadata) {
                    try{
                        state = storedMetadata == -1
                            ? {} : JSON.parse(storedMetadata);
                    }
                    catch (e){ state = {} }

                    // There's a hash. Lets compare it to the hash of the
                    // current value. If they are the same we can keep the
                    // undo stack, otherwise we'll clear the undo stack
                    if (state.hash && typeof storedValue == "string") {
                        state.value = storedValue;

                        hash(storedValue, function(err, hash) {
                            done(state, state.hash != hash);
                        });
                        return; // Wait until hash is retrieved
                    }
                    else if (state.value && tab.path) {
                        // If the stored value is not the same as the value
                        // on disk we need to find out which is newer
                        if (state.value != storedValue)
                            compareModified = true;
                    }
                    else {
                        state.value = storedValue;
                    }

                    done(state);
                }
            }
        }

        hash.counter = 0;
        function hash(data, callback) {
            if (!worker) {
                worker = new Worker('/static/lib/rusha/rusha.min.js');
                worker.addEventListener("message", function(e) {
                    // @todo security?

                    if (jobs[e.data.id]) {
                        jobs[e.data.id](null, e.data.hash);
                        delete jobs[e.data.id];
                    }
                });
            }
            worker.postMessage({ id: ++hash.counter, data: data });
            jobs[hash.counter] = callback;

            if (hash.counter === 30000)
                hash.counter = 0;
        }

        /***** Lifecycle *****/

        plugin.on("load", function(){
            load();
        });
        plugin.on("enable", function(){

        });
        plugin.on("disable", function(){

        });
        plugin.on("unload", function(){
            loaded = false;
            clearInterval(timer);
        });

        /***** Register and define API *****/

        /**
         * Manages metadata for tabs in Cloud9. Each tab in Cloud9 has
         * additional information that needs to be stored.
         *
         * When you open a file in Cloud9, it generally is opened in a tab and
         * displayed using the {@link ace.Ace Ace} editor. The ace editor maintains a
         * lot of state while displaying the file, such as the scroll position,
         * the selection, the folds, the syntax highligher, etc. The document
         * also serializes the value and the complete undo stack. Editors
         * that don't open files can still hold metadata. The {@link terminal.Terminal Terminal}
         * for instance has selection, scroll state and scroll history. All this
         * information can be saved to disk by the metadata plugin.
         *
         * The metadata is saved in ~/.c9/metadata. The metadata plugin plugs
         * into the tabManager and takes over the loading of the file content
         * so that the loading of the content and the metadata is synchronized.
         * This plugin is also responsible for saving the metadata back to the
         * workspace.
         *
         * @singleton
         **/
        plugin.freezePublicAPI({

        });

        register(null, {
            metadata: plugin
        });
    }
});
<commit_msg>do not allow disabling metadata since that breaks collab<commit_after>define(function(require, exports, module) {
    main.consumes = [
        "c9", "Plugin", "fs", "settings", "tabManager", "dialog.error",
        "dialog.question", "preferences", "save"
    ];
    main.provides = ["metadata"];
    return main;

    function main(options, imports, register) {
        var c9 = imports.c9;
        var Plugin = imports.Plugin;
        var fs = imports.fs;
        var settings = imports.settings;
        var save = imports.save;
        var tabs = imports.tabManager;
        var confirm = imports["dialog.question"].show;
        var showError = imports["dialog.error"].show;
        var prefs = imports.preferences;

        /***** Initialization *****/

        var plugin = new Plugin("Ajax.org", main.consumes);
        var emit = plugin.getEmitter();

        var PATH = options.path || "/.c9/metadata";
        var WORKSPACE = "/workspace";

        var jobs = {};
        var changed = {};
        var cached = {};
        var worker, timer;

        var CHANGE_CHECK_INTERVAL = options.changeCheckInterval || 30000;

        var loaded = false;
        function load(){
            if (loaded) return false;
            loaded = true;

            // Schedule for inspection when tab becomes active
            tabs.on("tabAfterActivate", function(e) {
                // // If disabled don't do anything
                // if (!e.tab.loaded || !settings.getBool("user/metadata/@enabled"))
                //     return;

                if (e.lastTab)
                    changed[e.lastTab.name] = e.lastTab;

                changed[e.tab.name] = e.tab;
            }, plugin);

            // Closing a tab
            tabs.on("tabAfterClose", function (e) {
                // // If disabled don't do anything
                // if (!settings.getBool("user/metadata/@enabled"))
                //     return;

                var doc = e.tab.document;
                if (!e.tab.path) {
                    fs.unlink(PATH + "/" + e.tab.name, function(){ return false });
                }
                else if (doc.meta.newfile || doc.meta.$ignoreSave) {
                    fs.unlink(PATH + WORKSPACE + e.tab.path, function(){ return false });
                }
                else if (check(e.tab) !== false) {
                    delete changed[e.tab.name];
                    delete cached[e.tab.name];
                }
            }, plugin);

            // Opening a file
            tabs.on("beforeOpen", function(e) {
                // // If disabled don't do anything
                // if (!settings.getBool("user/metadata/@enabled"))
                //     return;

                // Don't load metadata if document state is defined or value is set
                if (e.tab.path && e.options.document.filter === false
                  || !e.tab.path && !e.options.document.filter
                  || e.options.value)
                    return;

                // todo should tabmanager check this?
                e.options.loadFromDisk = e.loadFromDisk
                    && !e.tab.document.meta.newfile
                    && !e.tab.document.meta.nofs;

                // Fetch the metadata and real data
                var callback = function(err) {
                    if (e.loadFromDisk)
                        e.callback(err);
                };
                loadMetadata(e.tab, e.options, callback, e.options.init);

                return e.loadFromDisk ? false : true;
            }, plugin);

            // Check every half a minute for changed tabs
            timer = setInterval(function(){
                checkChangedTabs();
            }, CHANGE_CHECK_INTERVAL);

            // Delete metadata when file is renamed
            save.on("saveAs", function(e){
                if (e.path != e.oldPath)
                    fs.unlink(PATH + WORKSPACE + e.oldPath, function(){ return false });
            });

            // Settings

            settings.on("read", function(e) {
                settings.setDefaults("user/metadata", [
                    // ["enabled", "true"],
                    ["undolimit", "100"],
                ]);
            }, plugin);

            settings.on("write", function(e) {
                if (e.unload) return;

                checkChangedTabs();
            }, plugin);

            function checkChangedTabs(unload) {
                // // If disabled don't do anything
                // if (!settings.getBool("user/metadata/@enabled"))
                //     return;

                tabs.getPanes().forEach(function(pane) {
                    var tab = pane.getTab();
                    if (tab) {
                        changed[tab.name] = tab;
                    }
                });

                for (var name in changed) {
                    if (check(changed[name], unload) === false)
                        return;
                }

                changed = {};
            }

            // Preferences

            prefs.add({
                "File" : {
                    position: 150,
                    "Meta Data" : {
                        position: 200,
                        "Store Meta Data of Opened Files" : {
                            type: "checkbox",
                            path: "user/metadata/@enabled",
                            position: 100
                        },
                        "Maximum of Undo Stack Items in Meta Data" : {
                            type: "spinner",
                            path: "user/metadata/@undolimit",
                            position: 200,
                            min: 10,
                            max: 10000
                        }
                    }
                }
            }, plugin);

            // Exiting Cloud9
            c9.on("beforequit", function(){
                checkChangedTabs(true);
            }, plugin);

            // Initial Load
            tabs.getTabs().forEach(function(tab) {
                var options = tab.getState();
                options.loadFromDisk = tab.path
                  && !tab.document.meta.newfile
                  && !tab.document.meta.nofs
                  // autoload to false prevents loading data, used by image editor
                  && (!tab.editor || tab.editor.autoload !== false);

                loadMetadata(tab, options, function(err) {
                    if (err) {
                        tab.unload();
                        showError("File not found '" + tab.path + "'");
                        return;
                    }
                    tab.classList.remove("loading");
                }, true);
            });
        }

        /***** Methods *****/

        function check(tab, forceSync) {
            var docChanged = tab.document.changed || tab.document.meta.nofs;

            // Don't save state if we're offline
            if (!c9.has(c9.STORAGE))
                return false;

            if (tab.meta.$loadingMetadata)
                return;

            // Ignore metadata files and preview pages and debug files and
            // tabs that are not loaded
            if (!tab.loaded
              || tab.path && tab.path.indexOf(PATH) === 0
              || tab.document.meta.preview)
                return;

            var state = tab.document.getState();

            // Make sure timestamp is preserved
            if (state.meta)
                state.timestamp = state.meta.timestamp;

            // meta is recorded by the tab state
            delete state.meta;

            // If we discarded the file before closing, clear that data
            if (tab.document.meta.$ignoreSave) {
                delete state.value;
                delete state.changed;
                delete state.undoManager;
                docChanged = true;
            }

            if (docChanged || typeof state.value == "undefined" || forceSync) {
                if (forceSync && !docChanged && state.undoManager.stack.length)
                    delete state.value;

                write(forceSync);
            }
            else {
                hash(state.value, function(err, hash) {
                    if (err) return;

                    delete state.value;
                    delete state.changed;
                    state.hash = hash;
                    write(forceSync);
                });
            }

            function write(forceSync) {
                if (c9.readonly) return;

                var limit = settings.getNumber("user/metadata/@undolimit");
                var undo = state.undoManager;
                if (undo) {
                    var start = Math.max(0, undo.position - limit);
                    undo.stack.splice(0, start);
                    undo.position -= start;
                    undo.mark     -= start;
                }

                try {
                    // This throws when a structure is circular
                    var sstate = JSON.stringify(state);
                } catch (e) {
                    // debugger;
                    return;
                }

                // Lets not save large metadata
                if (sstate.length > 1024 * 1024) {
                    sstate = "";
                    state = {};
                }

                if (cached[tab.name] != sstate) {
                    cached[tab.name] = sstate;

                    if (tab.path) {
                        var path = (tab.path.charAt(0) == "~" ? "/" : "") + tab.path;
                        fs.metadata(path, state, forceSync, function(err) {
                            if (err)
                                return;
                        });
                    }
                    else {
                        fs.metadata("/_/_/" + tab.name, state, forceSync, function(err) {
                            if (err)
                                return;
                        });
                    }
                }
            }

            return true;
        }

        function merge(from, to) {
            for (var prop in from) {
                if (to[prop] && typeof from[prop] == "object")
                    merge(from[prop], to[prop]);
                else
                    to[prop] = from[prop];
            }
        }

        function loadMetadata(tab, options, callback, init) {
            // // When something goes wrong somewhere in cloud9, this can happen
            // if (tab.path && "/~".indexOf(tab.path.charAt(0)) == -1)
            //     debugger;

            var path = tab.path
                ? PATH + WORKSPACE + (tab.path.charAt(0) == "~" ? "/" : "") + tab.path
                : PATH + "/" + tab.name;

            var storedValue, storedMetadata;
            var xhr;

            // Prevent Saving of Metadata
            tab.meta.$loadingMetadata = true;

            // Progress Handling
            tab.classList.add("loading");

            var loadStartT = Date.now();

            // Handler to show loading indicator
            function progress(loaded, total, complete) {
                var data = {
                    total: total,
                    loaded: loaded,
                    complete: complete,
                    dt: Date.now() - loadStartT
                };

                tab.document.progress(data);
            }

            if (tab.path) {
                if (options.loadFromDisk === false) {
                    // This is for new files and other files that will store
                    // their value in the metadata
                    receive(tab.document.value);

                    // Don't load metadata of newly created newfile tabs (runtime)
                    if (!init) {
                        receive(null, -1);
                        return;
                    }
                }
                else {
                    tab.classList.add("loading");
                    // progress(0, 1, 0);

                    var cb = function(err, data, metadata, res) {
                        if (err) return callback(err);
                        receive(data, metadata || -1);
                    };

                    xhr = emit("beforeReadFile", {
                        tab: tab,
                        path: tab.path,
                        callback: cb,
                        progress: progress
                    });

                    if (!xhr)
                        xhr = fs.readFileWithMetadata(tab.path, "utf8", cb, progress);
                }
            }

            if (!xhr) {
                xhr = fs.readFile(path, "utf8", function(err, data) {
                    receive(null, err ? -1 : data);
                }, progress);
            }

            // Cancel file opening when tab is closed
            var abort = function(){ xhr && xhr.abort(); };
            tab.on("close", abort);
            tabs.on("open", function wait(e) {
                if (e.tab == tab) {
                    tab.off("close", abort);
                    tab.off("open", wait);
                }
            }, tab);

            function receive(value, metadata) {
                var state;

                if (value !== null)
                    storedValue = value;
                if (metadata) {
                    storedMetadata = metadata;
                    if (metadata != -1) {
                        cached[tab.name]
                            = metadata.replace(/"timestamp":\d+\,?$/, "");
                    }
                }

                // Final state processing and then we're done
                var compareModified = false;
                function done(state, cleansed) {
                    // Import state from options
                    var doc = options.document;
                    if (doc instanceof Plugin)
                        doc = doc.getState();

                    delete doc.fullState;
                    delete doc.value;
                    delete doc.undoManager;

                    if (!doc.changed)
                        delete doc.changed;

                    if (cleansed) {
                        delete state.undoManager;

                        if (tab.editor && state[tab.editor.type])
                            state[tab.editor.type].cleansed = true;
                    }

                    // Preserve timestamp from metadata
                    if (!doc.meta) doc.meta = {};
                    doc.meta.timestamp = state.timestamp;
                    delete state.timestamp;

                    // Merge the two sources
                    merge(doc, state);

                    if (tab.document.hasValue())
                        delete state.value;

                    // Keep original value from disk
                    state.meta.$savedValue = storedValue;

                    var sameValue = state.value === storedValue;
                    if (options.loadFromDisk && (sameValue || compareModified)) {
                        fs.stat(tab.path, function(err, stat) {
                            if (err) return;

                            if (compareModified) {
                                // @todo this won't work well on windows, because
                                // there is a 20s period in which the mtime is
                                // the same. The solution would be to have a
                                // way to compare the saved document to the
                                // loaded document that created the state
                                if (!state.meta || state.meta.timestamp < stat.mtime) {
                                    var doc = tab.document;

                                    function checkChange(){
                                        confirm("File Changed",
                                          tab.path + " has been changed on disk.",
                                          "Would you like to reload this file?",
                                          function(){ // Yes
                                              // Set new value and clear undo state
                                              doc.setBookmarkedValue(storedValue, true);
                                              doc.meta.timestamp = stat.mtime;
                                          },
                                          function(){ // No
                                              // Set to changed
                                              doc.undoManager.bookmark(-2);
                                              doc.meta.timestamp = stat.mtime;
                                          },
                                          { merge: false, all: false }
                                        );
                                    }

                                    if (state.meta.preview) {
                                        doc.editor.on("focus", function wait(e) {
                                            if (doc.editor.activeDocument == doc) {
                                                doc.editor.off("focus", wait);
                                                checkChange();
                                            }
                                        }, doc);
                                        return;
                                    }
                                    else
                                        checkChange();
                                }
                            }
                            else {
                                tab.document.meta.timestamp = stat.mtime;
                            }
                        });
                    }

                    // Set new state
                    tab.document.setState(state);

                    // Declare done
                    delete tab.meta.$loadingMetadata;

                    callback();
                }

                if ((!tab.path || storedValue !== undefined) && storedMetadata) {
                    try{
                        state = storedMetadata == -1
                            ? {} : JSON.parse(storedMetadata);
                    }
                    catch (e){ state = {} }

                    // There's a hash. Lets compare it to the hash of the
                    // current value. If they are the same we can keep the
                    // undo stack, otherwise we'll clear the undo stack
                    if (state.hash && typeof storedValue == "string") {
                        state.value = storedValue;

                        hash(storedValue, function(err, hash) {
                            done(state, state.hash != hash);
                        });
                        return; // Wait until hash is retrieved
                    }
                    else if (state.value && tab.path) {
                        // If the stored value is not the same as the value
                        // on disk we need to find out which is newer
                        if (state.value != storedValue)
                            compareModified = true;
                    }
                    else {
                        state.value = storedValue;
                    }

                    done(state);
                }
            }
        }

        hash.counter = 0;
        function hash(data, callback) {
            if (!worker) {
                worker = new Worker('/static/lib/rusha/rusha.min.js');
                worker.addEventListener("message", function(e) {
                    // @todo security?

                    if (jobs[e.data.id]) {
                        jobs[e.data.id](null, e.data.hash);
                        delete jobs[e.data.id];
                    }
                });
            }
            worker.postMessage({ id: ++hash.counter, data: data });
            jobs[hash.counter] = callback;

            if (hash.counter === 30000)
                hash.counter = 0;
        }

        /***** Lifecycle *****/

        plugin.on("load", function(){
            load();
        });
        plugin.on("enable", function(){

        });
        plugin.on("disable", function(){

        });
        plugin.on("unload", function(){
            loaded = false;
            clearInterval(timer);
        });

        /***** Register and define API *****/

        /**
         * Manages metadata for tabs in Cloud9. Each tab in Cloud9 has
         * additional information that needs to be stored.
         *
         * When you open a file in Cloud9, it generally is opened in a tab and
         * displayed using the {@link ace.Ace Ace} editor. The ace editor maintains a
         * lot of state while displaying the file, such as the scroll position,
         * the selection, the folds, the syntax highligher, etc. The document
         * also serializes the value and the complete undo stack. Editors
         * that don't open files can still hold metadata. The {@link terminal.Terminal Terminal}
         * for instance has selection, scroll state and scroll history. All this
         * information can be saved to disk by the metadata plugin.
         *
         * The metadata is saved in ~/.c9/metadata. The metadata plugin plugs
         * into the tabManager and takes over the loading of the file content
         * so that the loading of the content and the metadata is synchronized.
         * This plugin is also responsible for saving the metadata back to the
         * workspace.
         *
         * @singleton
         **/
        plugin.freezePublicAPI({

        });

        register(null, {
            metadata: plugin
        });
    }
});
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2013 Lp digital system
 *
 * This file is part of BackBee.
 *
 * BackBee is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * BackBee is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with BackBee. If not, see <http://www.gnu.org/licenses/>.
 */

define('tb.component/translator/main', ['component!logger', 'jquery', 'Core'], function (Logger, jQuery, Core) {
    'use strict';

    /*
     * BackBee Translator component
     * Allow to set multiples dictionnary files
     *
     * Can be accessed throught templates using global function 'trans'
     * Ex:
{{ trans('hello_world') }}
 will return "Hello world"
     *
     * // /i18n/en_US/global.js
     * {
     *      'hello_world' : 'Hello world'
     * }
     *
     * @author Mickaël Andrieu <mickael.andrieu@lp-digital.fr>
     */
    var Translator = {

            /**
             * Initialize Of Translator
             * @param {Object} config
             */
            init: function (config) {
                this.config = config;
                this.base = this.config.base;
                this.default_locale = config.default_locale;
                this.catalogs = {};
                this.defineDefaultLocale();

                Core.set('trans', this.translate.bind(this));
            },

            /**
             * Define a locale according to current choice or browser
             */
            defineDefaultLocale: function () {
                var locale = localStorage.getItem('locale');

                if (null === locale) {
                    locale = navigator.language;

                    if (-1 !== locale.indexOf('-')) {
                        locale = locale.replace('-', '_');
                    } else {
                        locale = locale + '_' + locale.toUpperCase();
                    }
                }

                this.setLocale(locale);
            },

            /**
             * Return a current locale
             * @returns {String}
             */
            getLocale:  function () {
                return this.locale;
            },

            /**
             * Set the locale
             * @param {String} locale
             */
            setLocale: function (locale) {
                this.locale = locale;

                localStorage.setItem('locale', locale);
            },

            /**
             * Return a default locale
             * @returns {String}
             */
            getDefaultLocale: function () {
                return this.defaut_locale;
            },

            /**
             * Translate the key from the json file
             *
             * Translate with the current locale
             * else translate with the default locale
             * else show the key
             *
             * @param {String} key
             * @returns {String}
             */
            translate: function (key) {
                var catalog = this.getCatalog(this.locale),
                    translation;

                if (undefined !== catalog) {
                    translation = catalog[key];
                }

                if (undefined === translation) {
                    Logger.notice('The key "' + key + '" has not translation.');
                    translation = key;
                }

                return translation;
            },

            /**
             * Return a catalog corresponding with a current locale
             * @param {String} locale
             * @returns {Object}
             */
            getCatalog: function (locale) {
                if (undefined === locale) {
                    return undefined;
                }

                return this.catalogs[locale];
            },

            /**
             * Load the file of a catalog
             * @param {String} locale
             */
            loadCatalog: function (locale) {
                var self = this,
                    dfd = jQuery.Deferred(),
                    catalog = this.getCatalog(locale);

                if (undefined === locale) {
                    locale = this.locale;
                }

                if (undefined !== catalog) {
                    this.setLocale(locale);
                    dfd.resolve();
                }

                jQuery.ajax({
                    'url': self.base + '/' + locale + '/global.json',
                    'data': 'json',
                    'async': false
                }).done(function (response) {
                    if (typeof response === 'string') {
                        response = JSON.parse(response);
                    }

                    self.catalogs[locale] = response;
                    self.setLocale(locale);

                    dfd.resolve();
                }).fail(function (response) {
                    if (404 === response.status) {
                        self.loadCatalog(self.config.default_locale).done(function () {
                            dfd.resolve();
                        });
                    }
                });

                return dfd.promise();
            }
        };

    return Translator;
});
<commit_msg>Removed extra / from main.js global.json<commit_after>/*
 * Copyright (c) 2011-2013 Lp digital system
 *
 * This file is part of BackBee.
 *
 * BackBee is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * BackBee is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with BackBee. If not, see <http://www.gnu.org/licenses/>.
 */

define('tb.component/translator/main', ['component!logger', 'jquery', 'Core'], function (Logger, jQuery, Core) {
    'use strict';

    /*
     * BackBee Translator component
     * Allow to set multiples dictionnary files
     *
     * Can be accessed throught templates using global function 'trans'
     * Ex:
{{ trans('hello_world') }}
 will return "Hello world"
     *
     * // /i18n/en_US/global.js
     * {
     *      'hello_world' : 'Hello world'
     * }
     *
     * @author Mickaël Andrieu <mickael.andrieu@lp-digital.fr>
     */
    var Translator = {

            /**
             * Initialize Of Translator
             * @param {Object} config
             */
            init: function (config) {
                this.config = config;
                this.base = this.config.base;
                this.default_locale = config.default_locale;
                this.catalogs = {};
                this.defineDefaultLocale();

                Core.set('trans', this.translate.bind(this));
            },

            /**
             * Define a locale according to current choice or browser
             */
            defineDefaultLocale: function () {
                var locale = localStorage.getItem('locale');

                if (null === locale) {
                    locale = navigator.language;

                    if (-1 !== locale.indexOf('-')) {
                        locale = locale.replace('-', '_');
                    } else {
                        locale = locale + '_' + locale.toUpperCase();
                    }
                }

                this.setLocale(locale);
            },

            /**
             * Return a current locale
             * @returns {String}
             */
            getLocale:  function () {
                return this.locale;
            },

            /**
             * Set the locale
             * @param {String} locale
             */
            setLocale: function (locale) {
                this.locale = locale;

                localStorage.setItem('locale', locale);
            },

            /**
             * Return a default locale
             * @returns {String}
             */
            getDefaultLocale: function () {
                return this.defaut_locale;
            },

            /**
             * Translate the key from the json file
             *
             * Translate with the current locale
             * else translate with the default locale
             * else show the key
             *
             * @param {String} key
             * @returns {String}
             */
            translate: function (key) {
                var catalog = this.getCatalog(this.locale),
                    translation;

                if (undefined !== catalog) {
                    translation = catalog[key];
                }

                if (undefined === translation) {
                    Logger.notice('The key "' + key + '" has not translation.');
                    translation = key;
                }

                return translation;
            },

            /**
             * Return a catalog corresponding with a current locale
             * @param {String} locale
             * @returns {Object}
             */
            getCatalog: function (locale) {
                if (undefined === locale) {
                    return undefined;
                }

                return this.catalogs[locale];
            },

            /**
             * Load the file of a catalog
             * @param {String} locale
             */
            loadCatalog: function (locale) {
                var self = this,
                    dfd = jQuery.Deferred(),
                    catalog = this.getCatalog(locale);

                if (undefined === locale) {
                    locale = this.locale;
                }

                if (undefined !== catalog) {
                    this.setLocale(locale);
                    dfd.resolve();
                }

                jQuery.ajax({
                    'url': self.base + locale + '/global.json',
                    'data': 'json',
                    'async': false
                }).done(function (response) {
                    if (typeof response === 'string') {
                        response = JSON.parse(response);
                    }

                    self.catalogs[locale] = response;
                    self.setLocale(locale);

                    dfd.resolve();
                }).fail(function (response) {
                    if (404 === response.status) {
                        self.loadCatalog(self.config.default_locale).done(function () {
                            dfd.resolve();
                        });
                    }
                });

                return dfd.promise();
            }
        };

    return Translator;
});
<|endoftext|>


<commit_before>// This file contains a package.json for the dependencies of the command-line
// tool.

// We put this in a JS file so that it can contain comments. It is processed
// into a package.json file by generate-dev-bundle.sh.

var packageJson = {
  name: "meteor-dev-bundle-tool",
  // Version is not important but is needed to prevent warnings.
  version: "0.0.0",
  dependencies: {
    // Explicit dependency because we are replacing it with a bundled version
    // and we want to make sure there are no dependencies on a higher version
    npm: "3.10.5",
    "node-gyp": "3.4.0",
    "node-pre-gyp": "0.6.29",
    "meteor-babel": "0.12.0",
    "meteor-promise": "0.7.2",
    fibers: "1.0.13",
    promise: "7.1.1",
    // So that Babel 6 can emit require("babel-runtime/helpers/...") calls.
    "babel-runtime": "6.9.2",
    // For various ES2015 polyfills, such as Map and Set.
    "meteor-ecmascript-runtime": "0.2.9",
    // Not yet upgrading Underscore from 1.5.2 to 1.7.0 (which should be done
    // in the package too) because we should consider using lodash instead
    // (and there are backwards-incompatible changes either way).
    underscore: "1.5.2",
    "source-map-support": "https://github.com/meteor/node-source-map-support/tarball/1912478769d76e5df4c365e147f25896aee6375e",
    semver: "4.1.0",
    request: "2.47.0",
    fstream: "https://github.com/meteor/fstream/tarball/cf4ea6c175355cec7bee38311e170d08c4078a5d",
    tar: "1.0.2",
    kexec: "2.0.2",
    "source-map": "0.5.3",
    "browserstack-webdriver": "2.41.1",
    "node-inspector": "0.12.8",
    chalk: "0.5.1",
    sqlite3: "3.1.3",
    netroute: "1.0.2",
    "http-proxy": "1.11.1",
    "wordwrap": "0.0.2",
    "moment": "2.8.4",
    "rimraf": "2.4.3",
    // XXX: When we update this, see if it fixes this Github issue:
    // https://github.com/jgm/CommonMark/issues/276 . If it does, remove the
    // workaround from the tool.
    "commonmark": "0.15.0",
    escope: "3.2.0",
    // 2.4.0 (more or less, the package.json change isn't committed) plus our PR
    // https://github.com/williamwicks/node-eachline/pull/4
    eachline: "https://github.com/meteor/node-eachline/tarball/ff89722ff94e6b6a08652bf5f44c8fffea8a21da",
    pathwatcher: "6.7.0",
    runas: "3.1.1",
    'lru-cache': '2.6.4',
    'cordova-lib': "6.0.0",
    longjohn: '0.2.11'
  }
};

if (process.platform === 'win32') {
  // Remove dependencies that do not work on Windows
  delete packageJson.dependencies.netroute;
  delete packageJson.dependencies.kexec;
}

process.stdout.write(JSON.stringify(packageJson, null, 2) + '\n');
<commit_msg>Upgrade npm tar package to v2.2.1.<commit_after>// This file contains a package.json for the dependencies of the command-line
// tool.

// We put this in a JS file so that it can contain comments. It is processed
// into a package.json file by generate-dev-bundle.sh.

var packageJson = {
  name: "meteor-dev-bundle-tool",
  // Version is not important but is needed to prevent warnings.
  version: "0.0.0",
  dependencies: {
    // Explicit dependency because we are replacing it with a bundled version
    // and we want to make sure there are no dependencies on a higher version
    npm: "3.10.5",
    "node-gyp": "3.4.0",
    "node-pre-gyp": "0.6.29",
    "meteor-babel": "0.12.0",
    "meteor-promise": "0.7.2",
    fibers: "1.0.13",
    promise: "7.1.1",
    // So that Babel 6 can emit require("babel-runtime/helpers/...") calls.
    "babel-runtime": "6.9.2",
    // For various ES2015 polyfills, such as Map and Set.
    "meteor-ecmascript-runtime": "0.2.9",
    // Not yet upgrading Underscore from 1.5.2 to 1.7.0 (which should be done
    // in the package too) because we should consider using lodash instead
    // (and there are backwards-incompatible changes either way).
    underscore: "1.5.2",
    "source-map-support": "https://github.com/meteor/node-source-map-support/tarball/1912478769d76e5df4c365e147f25896aee6375e",
    semver: "4.1.0",
    request: "2.47.0",
    fstream: "https://github.com/meteor/fstream/tarball/cf4ea6c175355cec7bee38311e170d08c4078a5d",
    tar: "2.2.1",
    kexec: "2.0.2",
    "source-map": "0.5.3",
    "browserstack-webdriver": "2.41.1",
    "node-inspector": "0.12.8",
    chalk: "0.5.1",
    sqlite3: "3.1.3",
    netroute: "1.0.2",
    "http-proxy": "1.11.1",
    "wordwrap": "0.0.2",
    "moment": "2.8.4",
    "rimraf": "2.4.3",
    // XXX: When we update this, see if it fixes this Github issue:
    // https://github.com/jgm/CommonMark/issues/276 . If it does, remove the
    // workaround from the tool.
    "commonmark": "0.15.0",
    escope: "3.2.0",
    // 2.4.0 (more or less, the package.json change isn't committed) plus our PR
    // https://github.com/williamwicks/node-eachline/pull/4
    eachline: "https://github.com/meteor/node-eachline/tarball/ff89722ff94e6b6a08652bf5f44c8fffea8a21da",
    pathwatcher: "6.7.0",
    runas: "3.1.1",
    'lru-cache': '2.6.4',
    'cordova-lib': "6.0.0",
    longjohn: '0.2.11'
  }
};

if (process.platform === 'win32') {
  // Remove dependencies that do not work on Windows
  delete packageJson.dependencies.netroute;
  delete packageJson.dependencies.kexec;
}

process.stdout.write(JSON.stringify(packageJson, null, 2) + '\n');
<|endoftext|>


<commit_before>var pkg = require('../../package.json');

/**
 * Get the value of a CLI argument
 *
 * @param {String} name
 * @param {Array} args
 * @api private
 */
 function getArgument(name, args) {
  var flags = args || process.argv.slice(2),
    index = flags.lastIndexOf(name);

  if (index === -1 || index + 1 >= flags.length) {
    return null;
  }

  return flags[index + 1];
}

/**
 * Get the value of reject-unauthorized
 * If environment variable SASS_REJECT_UNAUTHORIZED is non-zero,
 * .npmrc variable sass_reject_unauthorized or
 * process argument --sass-reject_unauthorized is provided,
 * set rejectUnauthorized to true
 * Else set to false by default
 *
 * @return {Boolean} The value of rejectUnauthorized
 * @api private
 */
module.exports = function() {
  var rejectUnauthorized = false;

  if (getArgument('--sass-reject-unauthorized')) {
    rejectUnauthorized = getArgument('--sass-reject-unauthorized');
  } else if (process.env.SASS_REJECT_UNAUTHORIZED !== '0') {
    rejectUnauthorized = true;
  } else if (process.env.npm_config_sass_reject_unauthorized) {
    rejectUnauthorized = process.env.npm_config_sass_reject_unauthorized;
  } else if (pkg.nodeSassConfig && pkg.nodeSassConfig.rejectUnauthorized) {
    rejectUnauthorized = pkg.nodeSassConfig.rejectUnauthorized;
  }

  return rejectUnauthorized;
};
<commit_msg>Lint fix<commit_after>var pkg = require('../../package.json');

/**
 * Get the value of a CLI argument
 *
 * @param {String} name
 * @param {Array} args
 * @api private
 */
function getArgument(name, args) {
  var flags = args || process.argv.slice(2),
    index = flags.lastIndexOf(name);

  if (index === -1 || index + 1 >= flags.length) {
    return null;
  }

  return flags[index + 1];
}

/**
 * Get the value of reject-unauthorized
 * If environment variable SASS_REJECT_UNAUTHORIZED is non-zero,
 * .npmrc variable sass_reject_unauthorized or
 * process argument --sass-reject_unauthorized is provided,
 * set rejectUnauthorized to true
 * Else set to false by default
 *
 * @return {Boolean} The value of rejectUnauthorized
 * @api private
 */
module.exports = function() {
  var rejectUnauthorized = false;

  if (getArgument('--sass-reject-unauthorized')) {
    rejectUnauthorized = getArgument('--sass-reject-unauthorized');
  } else if (process.env.SASS_REJECT_UNAUTHORIZED !== '0') {
    rejectUnauthorized = true;
  } else if (process.env.npm_config_sass_reject_unauthorized) {
    rejectUnauthorized = process.env.npm_config_sass_reject_unauthorized;
  } else if (pkg.nodeSassConfig && pkg.nodeSassConfig.rejectUnauthorized) {
    rejectUnauthorized = pkg.nodeSassConfig.rejectUnauthorized;
  }

  return rejectUnauthorized;
};
<|endoftext|>