Ajax.InPlaceEditorでバリデーションに引っかかったら

nil.to_sが”nil”になるような言語は(ry というのは置いといて、まだまだPythonをリハビリ中。 Rubyより関数志向での開発がしやすくて楽しいですよねえ。

リハビリを兼ねてweb.pyで個人的なツールを作ってます。web.pyはシンプルで軽いので、個人用途(非公開でツールとして使う)だったらレンタルサーバーでCGIとして動作させても問題なさそうです。(XREAでは簡単なものなら負荷率0ptでした。Railsとかならいれるだけでダメなんで、素晴らしい)

そこで、scriptaculousのAjax.InPlaceEditorを使っているわけですが、困ったことがひとつ。InPlace___Editor___なわけで、値を当然入力します。でその値がサーバー側でバリデーションエラーな時どうしたもんかと。

理想的な動作としては

  • エラーをユーザーに通知する
  • サブミットする前の値のままtextareaを表示しておく

なんですが、コンストラクタの中のoptionsあたりをのぞいてもそれらしきオプションはなさげ。

ということでとりあえず場当たり的に書いてみたものが以下。

(function(){
Ajax.RollbackableInPlaceEditor = Class.create();
var dummy = function(){};
dummy.prototype = Ajax.InPlaceEditor.prototype;
Ajax.RollbackableInPlaceEditor.prototype = new dummy;
Ajax.RollbackableInPlaceEditor.prototype.constructor = Ajax.RollbackableInPlaceEditor;
})();
Object.extend(Ajax.RollbackableInPlaceEditor.prototype, {
  initialize : function(element, url, options) {
    var self = this;
    options = Object.extend({
      callback: function(form) {
        self.oldValue = self.editField.value;
        return Form.serialize(form);
      },
      onFailure : Prototype.emptyFunction
    }, options || {});
    Ajax.InPlaceEditor.prototype.initialize.apply(this, [element, url, options]);
  },
  onclickCancel: function() {
    this.onComplete();
    this.element.innerHTML = this._oldInnerHTML;
    this.element.show();
    return false;
  },
  onComplete: function(transport) {
    this.leaveEditMode();
    if(transport && !Ajax.Base.prototype.responseIsSuccess.call({transport:transport})) {
      this.options.onFailure.bind(this)(transport, this.element);
      return this.enterEditMode();
    }else {
      this.oldValue = null;
    }
    this.options.onComplete.bind(this)(transport, this.element);
  },
  onFailure: function(transport) {
    return false;
  },
  getText : function() {
     if(this.oldValue != null && this.oldValue != undefined){var v = this.oldValue; this.oldValue = null; return v;}
    this._oldInnerHTML = this.element.innerHTML;
    return this.element.innerHTML;
  }
});

サーバー側でエラーがあったときは適当に500とか406とかでレスポンスを返せばオッケーです。

なのでサーバー側ではたとえばweb.pyなら

# errors = ['データが長すぎます。'] など
if len(errors) != 0:
  web.header("Content-Type", "text/javascript"), 
  web.ctx["status"] = "406 Not Acceptable"
  print "".join(["alert('", "\n".join(errors), "');"])
  return 

とすればエラーになって(エラーメッセージがアラートされる)、サブミットした内容のままで再度編集できます。

豆知識ですが、以上のようにサーバー側でtext/javascriptでレスポンスを返すとprototype.jsでは自動的にjavascriptとして評価してくれます。

うーむ、まさに場当たり的。いろいろまずそうだけど、まぁ動いてるっぽいし気にしないことにしとこう・・・・

comments powered by Disqus