OSDN Git Service

daa65afba9a6a9d8c0bf47cbc3186275ac52e947
[sie/sie.git] / tool / funcproto / base.js
1 /*!SIE under the MIT Lisence\r
2  */\r
3 /*! Copyright 2016 dhrname and other contributors\r
4  * http://sie.osdn.jp/\r
5  *\r
6  * Permission is hereby granted, free of charge, to any person obtaining\r
7  * a copy of this software and associated documentation files (the\r
8  * "Software"), to deal in the Software without restriction, including\r
9  * without limitation the rights to use, copy, modify, merge, publish,\r
10  * distribute, sublicense, and/or sell copies of the Software, and to\r
11  * permit persons to whom the Software is furnished to do so, subject to\r
12  * the following conditions:\r
13  * \r
14  * The above copyright notice and this permission notice shall be\r
15  * included in all copies or substantial portions of the Software.\r
16  * \r
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
24  */\r
25 \r
26 \r
27 (function(){\r
28 \r
29 /*本体オブジェクト。base関数の裏に隠蔽されている*/\r
30 var _base = {\r
31     \r
32     /*_base.objはbase関数やupメソッドで呼び出されるオブジェクトの始祖となるオブジェクト*/\r
33     obj: {\r
34       /*upメソッド\r
35        * 自身をプロトタイプとして、新たにオブジェクトを生成する\r
36        */\r
37       up: function(name) {\r
38         var s = Object.create(this);\r
39         if (name) {\r
40           this[name] = s;\r
41           s.up = this.up;\r
42         } else {\r
43           /*既定値を$1としておく*/\r
44           this.$1 = s;\r
45         }\r
46         return s;\r
47       },\r
48     \r
49       /*mixメソッド\r
50        * 別のオブジェクトと合成ができるメソッド\r
51        */\r
52       mix: function(obj) {\r
53         if (!obj) {\r
54           throw new Error("No arguments error");\r
55         }\r
56         if (typeof obj !== "function") {\r
57           var alias = _base.__ng_;\r
58           for (var i in obj) {\r
59             if (!alias[i]) {\r
60               /*hasOwnPropertyメソッドを使わないのは、プロトタイプチェーンをたどるようにするため\r
61                *なお、Object.prototypeのプロパティなどは外した方がエラーがおきにくい\r
62                */\r
63               this[i] = obj[i];\r
64             }\r
65           }\r
66           i = alias = void 0;\r
67         } else {\r
68           obj.call(this, this);\r
69         }\r
70         return this;\r
71       },\r
72     \r
73       /*onメソッド\r
74        * メソッドの合成ができるメソッド。\r
75        * 指定した名前nameのメソッドが呼び出された場合、便乗して指定関数funcをメソッドとして実行することができる\r
76        */\r
77       on: function(name, func) {\r
78         if (!name) {\r
79           throw new Error("No arguments error");\r
80         } else if (/^(?:up|on|mix|of)$/.test(name)) {\r
81           throw new Error("Invalid method name error");\r
82         } else if (typeof func !== "function") {\r
83           throw new Error("Not support arguments type");\r
84         }\r
85         var tev = this._eventList__,\r
86             tn = this[name];\r
87         if (!this._eventList__) {\r
88           tev = this._eventList__ = [];\r
89         } else if (!this.hasOwnProperty("_eventList__")) { //祖先がすでにonメソッドを呼び出していれば\r
90           var s = [];\r
91           s._parent = tev;\r
92           tev = this._eventList__ = s;\r
93           s = void 0;\r
94         }\r
95         if (!this[name] || !tn.isOn) { //まだ、onメソッドが呼び出されていなければ\r
96           /*nameで指定されたメソッドの初期化*/\r
97           if (typeof tn === "function") {\r
98             /*nameで指定されたメソッドがすでにある場合は、配列tevの親をたどれないようにしておく*/\r
99             tev.push({\r
100                 name: name,\r
101                 func: tn\r
102               });\r
103             tev._parent = null;\r
104           }\r
105           this[name] = function() {\r
106             var te = this._eventList__,\r
107                  _name = name,    //スコープチェーンのエイリアス\r
108                  ts = null,\r
109                  s = null,\r
110                  tp,\r
111                  isCalled = false;//返り値の制御で使う\r
112             te._child = null;\r
113             while (tp = te._parent) { //親をさかのぼっていく\r
114               tp._child = te;\r
115               te = tp;\r
116             }\r
117             while (te) {            //子をたどっていく\r
118               /*最初の返り値の結果はsとして記録して、後で返す*/\r
119               for (var i=0, tli=te.length;i<tli;++i) {\r
120                 if(te[i].name === _name) {\r
121                   ts = te[i].func.apply(this, arguments);\r
122                   if (!isCalled) {\r
123                     s = ts;\r
124                     isCalled = true;\r
125                   }\r
126                 }\r
127               }\r
128               te = te._child;\r
129             }\r
130             te = ts = _name = isCalled = void 0;\r
131             return s;\r
132           };\r
133           this[name].isOn = true;\r
134         }\r
135         tev.push({\r
136                 name: name,\r
137                 func: func\r
138               });\r
139         tev = tn = func= void 0;\r
140         return this;\r
141       },\r
142 \r
143       /*__argsと__appプロパティは後のofメソッドで使う*/\r
144       __args: null,\r
145       __app: null,\r
146 \r
147       /*ofメソッド\r
148        * 指定されたオブジェクトのプロパティを遅延処理で実行できるメソッド\r
149        * 後述のcallメソッドと組み合わせて使う\r
150        */\r
151        of: function(obj) {\r
152         if (!obj) {\r
153           throw new Error("No arguments error");\r
154         } else if(this.hasOwnProperty("__of")) {\r
155           /*再代入禁止*/\r
156           throw new Error("Reset error");\r
157         }\r
158         /*__appと__argsプロパティに、指定されたプロパティを記録しておく*/\r
159         var args = this.__args || [];\r
160         for (var i in obj) {\r
161           if(obj.hasOwnProperty(i) && (i !== "call")) {\r
162             /*一度登録されたプロパティは二度書きしないようにする*/\r
163             args[i] || args.push(i);\r
164             args[i] = this[i] = obj[i];\r
165           }\r
166         }\r
167         obj.call && (this.__app = { call: obj.call });\r
168         this.__args = args;\r
169         this.__of = 1;\r
170         args = i = obj = void 0;\r
171         return this;\r
172        },\r
173 \r
174       /*callメソッド\r
175        * ofメソッドで指定されているオブジェクトのcallメソッドを実行できるメソッド\r
176        * そのさい、オブジェクトのプロパティとメソッドは、自動で実行展開される\r
177        */\r
178        call: function() {\r
179          if (!this.__app) { //ofメソッドが呼び出されていないか、callメソッドが一度も設定されていない場合\r
180            return this;\r
181          }\r
182          var args = this.__args,\r
183              call = this.call; //callメソッドの一時的なキャッシュ\r
184          /*循環参照を避けるためcallメソッドの入れ替え*/\r
185          this.call = this.callFunc;\r
186          for (var i=0, ali=args.length;i<ali;++i) {\r
187            /*callメソッドがあるオブジェクトは展開*/\r
188            var ai = args[i],\r
189                argi = this[ai];\r
190            if (argi && argi.call) {\r
191              this[ai] = argi.call(this);\r
192            }\r
193          }\r
194          this.call = call;\r
195          args = ai = argi = call = void 0;\r
196          return this.__app.call.apply(this, arguments);\r
197        },\r
198        callFunc: function() { return this; }\r
199     },\r
200 };\r
201 \r
202 /*base関数でキャッシュとして使うオブジェクト*/\r
203 var baseCache = {};\r
204 \r
205 base = function (name) {\r
206     var __base = _base,\r
207          _cache = baseCache; //エイリアス作成\r
208     if (!name) {\r
209       throw new Error("No arguments error");\r
210     } else if (_cache[name]) {\r
211       /*キャッシュに登録されている場合は、登録されたオブジェクトを返す*/\r
212       return _cache[name];\r
213     } else {\r
214       var s = Object.create(__base.obj);\r
215       this[name] = _cache[name] = s;\r
216       /*自身が値であるようなプロパティを設定する*/\r
217       s[name] = s;\r
218       return s;\r
219     }\r
220 };\r
221 \r
222 \r
223 /*mixメソッドで使うNGハッシュを作成*/\r
224 var hash = {},\r
225     proto = Object.prototype;\r
226 for (var i in proto) {\r
227   hash[i] = true;\r
228   /*上記のキャッシュについて、すべてのプロパティをnullかundefinedにしておく*/\r
229   baseCache[i] = null;\r
230 }\r
231 hash.constructor = false; //constructorはNGハッシュに追加しない\r
232 _base.__ng_ = hash;\r
233 hash = proto = void 0;\r
234 \r
235 /*base.free関数\r
236  *  即時関数の内部で作っていおいたオブジェクトを解放させるための関数\r
237  */\r
238 base.free = function() {\r
239   delete _base.obj;\r
240   _base = baseCache = callFunc = void 0;\r
241 };\r
242 \r
243 /*IE8などObject.createをサポートしていないブラウザ用*/\r
244 Object.create || (Object.create = function(obj) {\r
245   var F = function() {};\r
246   F.prototype = obj;\r
247   return new F()\r
248 } );\r
249 })();\r