[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/webroot/rsrc/js/application/differential/ -> DifferentialInlineCommentEditor.js (source)

   1  /**
   2   * @provides differential-inline-comment-editor
   3   * @requires javelin-dom
   4   *           javelin-util
   5   *           javelin-stratcom
   6   *           javelin-install
   7   *           javelin-request
   8   *           javelin-workflow
   9   */
  10  
  11  JX.install('DifferentialInlineCommentEditor', {
  12  
  13    construct : function(uri) {
  14      this._uri = uri;
  15    },
  16  
  17    events : ['done'],
  18  
  19    members : {
  20      _uri : null,
  21      _undoText : null,
  22      _skipOverInlineCommentRows : function(node) {
  23        // TODO: Move this semantic information out of class names.
  24        while (node && node.className.indexOf('inline') !== -1) {
  25          node = node.nextSibling;
  26        }
  27        return node;
  28      },
  29      _buildRequestData : function() {
  30        return {
  31          op : this.getOperation(),
  32          on_right : this.getOnRight(),
  33          id : this.getID(),
  34          number : this.getLineNumber(),
  35          is_new : this.getIsNew(),
  36          length : this.getLength(),
  37          changeset : this.getChangeset(),
  38          text : this.getText() || ''
  39        };
  40      },
  41      _draw : function(content, exact_row) {
  42        var row = this.getRow();
  43        var table = this.getTable();
  44        var target = exact_row ? row : this._skipOverInlineCommentRows(row);
  45  
  46        return copyRows(table, content, target);
  47      },
  48      _removeUndoLink : function() {
  49        var rows = JX.DifferentialInlineCommentEditor._undoRows;
  50        if (rows) {
  51          for (var ii = 0; ii < rows.length; ii++) {
  52            JX.DOM.remove(rows[ii]);
  53          }
  54        }
  55      },
  56      _undo : function() {
  57        this._removeUndoLink();
  58  
  59        this.setText(this._undoText);
  60        this.start();
  61      },
  62      _registerUndoListener : function() {
  63        if (!JX.DifferentialInlineCommentEditor._activeEditor) {
  64          JX.Stratcom.listen(
  65            'click',
  66            'differential-inline-comment-undo',
  67            function(e) {
  68              JX.DifferentialInlineCommentEditor._activeEditor._undo();
  69              e.kill();
  70            });
  71        }
  72        JX.DifferentialInlineCommentEditor._activeEditor = this;
  73      },
  74      _setRowState : function(state) {
  75        var is_hidden   = (state == 'hidden');
  76        var is_loading  = (state == 'loading');
  77        var row = this.getRow();
  78        JX.DOM.alterClass(row, 'differential-inline-hidden', is_hidden);
  79        JX.DOM.alterClass(row, 'differential-inline-loading', is_loading);
  80      },
  81      _didContinueWorkflow : function(response) {
  82        var drawn = this._draw(JX.$H(response).getNode());
  83  
  84        var op = this.getOperation();
  85        if (op == 'edit') {
  86          this._setRowState('hidden');
  87        }
  88  
  89        JX.DOM.find(
  90          drawn[0],
  91          'textarea',
  92          'differential-inline-comment-edit-textarea').focus();
  93  
  94        var oncancel = JX.bind(this, function(e) {
  95          e.kill();
  96  
  97          this._didCancelWorkflow();
  98  
  99          if (op == 'edit') {
 100            this._setRowState('visible');
 101          }
 102  
 103          JX.DOM.remove(drawn[0]);
 104        });
 105        JX.DOM.listen(drawn[0], 'click', 'inline-edit-cancel', oncancel);
 106  
 107        var onsubmit = JX.bind(this, function(e) {
 108          e.kill();
 109  
 110          JX.Workflow.newFromForm(e.getTarget())
 111            .setHandler(JX.bind(this, function(response) {
 112              JX.DOM.remove(drawn[0]);
 113              if (op == 'edit') {
 114                this._setRowState('visible');
 115              }
 116              this._didCompleteWorkflow(response);
 117            }))
 118            .start();
 119  
 120          JX.DOM.alterClass(drawn[0], 'differential-inline-loading', true);
 121        });
 122        JX.DOM.listen(
 123          drawn[0],
 124          ['submit', 'didSyntheticSubmit'],
 125          'inline-edit-form',
 126          onsubmit);
 127      },
 128      _didCompleteWorkflow : function(response) {
 129        var op = this.getOperation();
 130  
 131        // We don't get any markup back if the user deletes a comment, or saves
 132        // an empty comment (which effects a delete).
 133        if (response.markup) {
 134          this._draw(JX.$H(response.markup).getNode());
 135        }
 136  
 137        // These operations remove the old row (edit adds a new row first).
 138        var remove_old = (op == 'edit' || op == 'delete');
 139        if (remove_old) {
 140          JX.DOM.remove(this.getRow());
 141          var other_rows = this.getOtherRows();
 142          for(var i = 0; i < other_rows.length; ++i) {
 143            JX.DOM.remove(other_rows[i]);
 144          }
 145        }
 146  
 147        // Once the user saves something, get rid of the 'undo' option. A
 148        // particular case where we need this is saving a delete, when we might
 149        // otherwise leave around an 'undo' for an earlier edit to the same
 150        // comment.
 151        this._removeUndoLink();
 152  
 153        JX.Stratcom.invoke('differential-inline-comment-update');
 154        this.invoke('done');
 155      },
 156      _didCancelWorkflow : function() {
 157        this.invoke('done');
 158  
 159        var op = this.getOperation();
 160        if (op == 'delete') {
 161          // No undo for delete, we prompt the user explicitly.
 162          return;
 163        }
 164  
 165        var textarea;
 166        try {
 167          textarea = JX.DOM.find(
 168            document.body, // TODO: use getDialogRootNode() when available
 169            'textarea',
 170            'differential-inline-comment-edit-textarea');
 171        } catch (ex) {
 172          // The close handler is called whenever the dialog closes, even if the
 173          // user closed it by completing the workflow with "Save". The
 174          // JX.Workflow API should probably be refined to allow programmatic
 175          // distinction of close caused by 'cancel' vs 'submit'. Testing for
 176          // presence of the textarea serves as a proxy for detecting a 'cancel'.
 177          return;
 178        }
 179  
 180        var text = textarea.value;
 181  
 182        // If the user hasn't edited the text (i.e., no change from original for
 183        // 'edit' or no text at all), don't offer them an undo.
 184        if (text == this.getOriginalText() || text === '') {
 185          return;
 186        }
 187  
 188        // Save the text so we can 'undo' back to it.
 189        this._undoText = text;
 190  
 191        var templates = this.getTemplates();
 192        var template = this.getOnRight() ? templates.r : templates.l;
 193        template = JX.$H(template).getNode();
 194  
 195        // NOTE: Operation order matters here; we can't remove anything until
 196        // after we draw the new rows because _draw uses the old rows to figure
 197        // out where to place the comment.
 198  
 199        // We use 'exact_row' to put the "undo" text directly above the affected
 200        // comment.
 201        var exact_row = true;
 202        var rows = this._draw(template, exact_row);
 203  
 204        this._removeUndoLink();
 205  
 206        JX.DifferentialInlineCommentEditor._undoRows = rows;
 207      },
 208  
 209      start : function() {
 210        this._registerUndoListener();
 211  
 212        var data = this._buildRequestData();
 213  
 214        var op = this.getOperation();
 215  
 216  
 217        if (op == 'delete') {
 218          this._setRowState('loading');
 219          var oncomplete = JX.bind(this, this._didCompleteWorkflow);
 220          var onclose = JX.bind(this, function() {
 221            this._setRowState('visible');
 222            this._didCancelWorkflow();
 223          });
 224  
 225          new JX.Workflow(this._uri, data)
 226            .setHandler(oncomplete)
 227            .setCloseHandler(onclose)
 228            .start();
 229        } else {
 230          var handler = JX.bind(this, this._didContinueWorkflow);
 231  
 232          if (op == 'edit') {
 233            this._setRowState('loading');
 234          }
 235  
 236          new JX.Request(this._uri, handler)
 237            .setData(data)
 238            .send();
 239        }
 240  
 241        return this;
 242      }
 243    },
 244  
 245    statics : {
 246      /**
 247       * Global refernece to the 'undo' rows currently rendered in the document.
 248       */
 249      _undoRows : null,
 250  
 251      /**
 252       * Global listener for the 'undo' click associated with the currently
 253       * displayed 'undo' link. When an editor is start()ed, it becomes the active
 254       * editor.
 255       */
 256      _activeEditor : null
 257    },
 258  
 259    properties : {
 260      operation : null,
 261      row : null,
 262      otherRows: [],
 263      table : null,
 264      onRight : null,
 265      ID : null,
 266      lineNumber : null,
 267      changeset : null,
 268      length : null,
 269      isNew : null,
 270      text : null,
 271      templates : null,
 272      originalText : null
 273    }
 274  
 275  });


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1