buffalo1.0beta.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. /*
  2. * Buffalo Web Remoting, An amowa infrastructure facility, a web remoting library.
  3. *
  4. * Author: Michael Chen (mechiland AT gmail DoT com, http://michael.nona.name)
  5. *
  6. * Version: 1.0
  7. *
  8. */
  9. /**
  10. * @fileoverview Buffalo.js is the core component of the Buffalo web remoting.
  11. * This file encapuslate the Buffalo, BuffaloCall, BuffaloReply object, and
  12. * most of it's methods.
  13. *
  14. * @author Michael Chen mechiland@gmail.com http://michael.nona.name
  15. * @version 1.0
  16. */
  17. /**
  18. * BuffaloCall object.
  19. * In most case, you don't need to construct a BuffaloCall yourself. just use
  20. * buffalo.remoteCall(...) to make common use.
  21. *
  22. * @constructor
  23. * @param {String} methodname the remote call method name.
  24. * note: this method name is ONLY the method name, not the service name.
  25. * Buffalo will take care of the service name and url.
  26. */
  27. //window.onerror = function(){return false};
  28. function BuffaloCall(methodname){
  29. /**
  30. * The method name
  31. * @type String
  32. * @private
  33. */
  34. this.method = methodname;
  35. /**
  36. * The parameters.
  37. * @type Array
  38. * @private
  39. */
  40. this.params = [];
  41. return this;
  42. }
  43. /**
  44. * Set the remote call method name.
  45. *
  46. * @param {String} methodName the method name to set.
  47. */
  48. BuffaloCall.prototype.setMethod = function(methodName){
  49. if (!methodName) return;
  50. this.method = methodName;
  51. }
  52. /**
  53. * Add one paramter to this buffalo call. Buffalo will try to find type
  54. * of the data.
  55. *
  56. * @param {varient} data the param to be added.
  57. */
  58. BuffaloCall.prototype.addParameter = function(data){
  59. if (arguments.length==0) return;
  60. this.params[this.params.length] = data;
  61. }
  62. /**
  63. * Construct the call informatiton to a XML format,
  64. * prepare to be sent to the buffalo end point.
  65. *
  66. * @type String
  67. * @returns the xml format of this call.
  68. */
  69. BuffaloCall.prototype.xml = function(){
  70. var method = this.method;
  71. var xml = "";
  72. xml += "<burlap:call>\n";
  73. xml += "<method>" + method+ "</method>\n";
  74. for (var i = 0; i < this.params.length; i++){
  75. var data = this.params[i];
  76. xml += BuffaloCall.getParamXML(BuffaloCall.dataTypeOf(data),data) + "\n";
  77. }
  78. xml += "</burlap:call>";
  79. return xml; // for now
  80. }
  81. /**
  82. * Judge the type of the paramter. should never be invoked by outside.
  83. *
  84. * @private
  85. * @type String
  86. * @returns the type of the object.
  87. */
  88. BuffaloCall.dataTypeOf = function (o){
  89. var type = typeof(o);
  90. type = type.toLowerCase();
  91. switch(type){
  92. case "number":
  93. if (Math.round(o) == o) type = "int";
  94. else type = "double";
  95. break;
  96. case "object":
  97. var con = o.constructor;
  98. if (con == Date) type = "date";
  99. else if (con == Array) type = "list";
  100. else type = "map";
  101. break;
  102. }
  103. return type;
  104. }
  105. /**
  106. * Process the common value to a xml.
  107. * @private
  108. * @returns the xml format of the data
  109. */
  110. BuffaloCall.doValueXML = function(type,data){
  111. var xml = "<" + type + ">" + xmlEncode(data) + "</" + type + ">";
  112. return xml;
  113. }
  114. function xmlEncode(data) {
  115. var str = "";
  116. if (typeof(data) == "string") {
  117. str = data;
  118. } else {
  119. return data;
  120. }
  121. str = str.replace("&","&amp;");
  122. str = str.replace("<","&lt;");
  123. str = str.replace(">","&gt;");
  124. return str;
  125. }
  126. /**
  127. * Process the boolean paramter to xml.
  128. * @private
  129. */
  130. BuffaloCall.doBooleanXML = function(data){
  131. var value = (data==true)?1:0;
  132. var xml = "<boolean>" + value + "</boolean>";
  133. return xml;
  134. }
  135. /**
  136. * @private
  137. */
  138. BuffaloCall.doDateXML = function(data){
  139. var xml = "<date>";
  140. xml += dateToISO8609(data);
  141. xml += "</date>";
  142. return xml;
  143. }
  144. /**
  145. * @private
  146. */
  147. BuffaloCall.doArrayXML = function(data){
  148. var xml = "<list>\n";
  149. xml += "<type>" +""+ "</type>\n";
  150. xml += "<length>" +data.length+ "</length>\n";
  151. for (var i = 0; i < data.length; i++){
  152. xml += BuffaloCall.getParamXML(BuffaloCall.dataTypeOf(data[i]),data[i]) + "\n";
  153. }
  154. xml += "</list>\n";
  155. return xml;
  156. }
  157. /**
  158. * @private
  159. */
  160. BuffaloCall.doStructXML = function(data){
  161. var boClass = data[Buffalo.BOCLASS];
  162. // Default to hashMap
  163. var boType = "java.util.HashMap";
  164. if (typeof(boClass) != 'undefined' || boClass != null) {
  165. boType = boClass;
  166. }
  167. var xml = "<map>\n";
  168. xml += "<type>" +boType+ "</type>\n";
  169. for (var i in data){
  170. if (data[i] != boType) {
  171. xml += BuffaloCall.getParamXML(BuffaloCall.dataTypeOf(i),i)+"\n";
  172. xml += BuffaloCall.getParamXML(BuffaloCall.dataTypeOf(data[i]),data[i]) + "\n";
  173. }
  174. }
  175. xml += "</map>\n";
  176. return xml;
  177. }
  178. /**
  179. * @private
  180. */
  181. BuffaloCall.getParamXML = function(type,data){
  182. var xml;
  183. switch (type){
  184. case "date":
  185. xml = BuffaloCall.doDateXML(data);
  186. break;
  187. case "list":
  188. xml = BuffaloCall.doArrayXML(data);
  189. break;
  190. case "map":
  191. xml = BuffaloCall.doStructXML(data);
  192. break;
  193. case "boolean":
  194. xml = BuffaloCall.doBooleanXML(data);
  195. break;
  196. default:
  197. xml = BuffaloCall.doValueXML(type,data);
  198. break;
  199. }
  200. return xml;
  201. }
  202. /**
  203. * Convenient function to convert a Date object to a ISO8609 string format.
  204. * @private
  205. */
  206. function dateToISO8609(date){
  207. var year = new String(date.getYear());
  208. var month = leadingZero(new String(date.getMonth()+1));
  209. var day = leadingZero(new String(date.getDate()));
  210. var time = leadingZero(new String(date.getHours())) + leadingZero(new String(date.getMinutes())) + leadingZero(new String(date.getSeconds()));
  211. var converted = year+month+day+"T"+time+"Z";
  212. return converted;
  213. }
  214. /**
  215. * leading zero.
  216. * @private
  217. */
  218. function leadingZero(n){
  219. // pads a single number with a leading zero. Heh.
  220. if (n.length==1) n = "0" + n;
  221. return n;
  222. }
  223. /**
  224. * A burlap reply object hold the remote call's result, and convert the
  225. * result xml to a object. This is one of the core object in the buffalo
  226. * web remoting. You should know the methods and properties very clearly.
  227. *
  228. * @constructor
  229. * @param {String} sourceXML the reply sourceXML
  230. */
  231. function BuffaloReply(sourceXML) {
  232. // define the primary properties
  233. /**@private*/
  234. this._source = sourceXML;
  235. /**@private*/
  236. this._isFault = false;
  237. /**@private*/
  238. this._type = "null";
  239. /**@private*/
  240. this._objects = [];
  241. /**@private*/
  242. this._objectNodes = [];
  243. var xmldoc = XmlDocument.create();
  244. xmldoc.async=false;
  245. xmldoc.loadXML(sourceXML);
  246. var root = xmldoc.documentElement;
  247. /**@private*/
  248. this._root = root;
  249. var dataNode = root.firstChild;
  250. /**@private*/
  251. this._type = BuffaloReply._getType(dataNode);
  252. /**
  253. * get the reply data type. The reply type will be:
  254. * boolean, date, double, int, long, list, map, null, ref, string, xml or fault.
  255. * base64 is not supported. (do you want to use base64 at the client side?)
  256. *
  257. * @type String
  258. * @returns the reply's data type
  259. *
  260. */
  261. this.getType = function() {
  262. return this._type;
  263. }
  264. /**
  265. * Get the result object. the returned type is differed by the type,
  266. * such as: if type=="boolean", then getResult() is a boolean value.
  267. * the types are the same as burlap protocal.
  268. * here is the convert table:
  269. * <ul>
  270. * <li>boolean: a java script boolean value
  271. * <li>date: a javascript Date value
  272. * <li>double: a javascript float value, use parseFloat to convert
  273. * <li>int,long: a javascript int value, use parseInt to convert
  274. * <li>list: a javascript Array object
  275. * <li>map: a javascript Object
  276. * <li>null: javascript null
  277. * <li>ref: a reference(pointer) to the specified javascript obejct.
  278. * <li>string, xml: a javascript string
  279. * <li>fault: a Fault object(NOT IMPLEMENTATED YET)
  280. * </ul>
  281. * @type varient
  282. * @returns the result object
  283. */
  284. this.getResult = function() {
  285. return this.deserialize(dataNode);
  286. }
  287. /**
  288. * if this is a fault reply
  289. * @type boolean
  290. * @return if this is a fault reply
  291. */
  292. this.isFault = function() {
  293. return (this._type == "fault");
  294. }
  295. /**
  296. * indicate if this a null reply
  297. * @type boolean
  298. * @returns if this is a null reply
  299. */
  300. this.isNull = function() {
  301. return (this._type == "null");
  302. }
  303. /**
  304. * get the source xml, the source xml is capable with the burlap reply.
  305. * @type String
  306. * @returns the reply source xml
  307. */
  308. this.getSource = function() {
  309. return this._source;
  310. }
  311. }
  312. /**
  313. * Deserialize the xml data node to a javascript object
  314. *
  315. * @private
  316. * @param {DOMElement} dataNode the dataNode
  317. * @returns the value of the dataNode
  318. */
  319. BuffaloReply.prototype.deserialize = function(dataNode) {
  320. var ret;
  321. type = BuffaloReply._getType(dataNode);
  322. switch (type) {
  323. case "boolean":
  324. ret = this.doBoolean(dataNode);
  325. break;
  326. case "date":
  327. ret = this.doDate(dataNode);
  328. break;
  329. case "double":
  330. ret = this.doDouble(dataNode);
  331. break;
  332. case "int":
  333. case "long":
  334. ret = this.doInt(dataNode);
  335. break;
  336. case "list":
  337. ret = this.doList(dataNode);
  338. break;
  339. case "map":
  340. ret = this.doMap(dataNode);
  341. break;
  342. case "null":
  343. ret = this.doNull(dataNode);
  344. break;
  345. case "ref":
  346. ret = this.doRef(dataNode);
  347. break;
  348. case "string":
  349. ret = this.doString(dataNode);
  350. break;
  351. case "xml":
  352. ret = this.doXML(dataNode);
  353. break;
  354. case "fault":
  355. ret = this.doFault(dataNode);
  356. break;
  357. default:
  358. ;
  359. }
  360. return ret;
  361. }
  362. /**
  363. * get the data type of the dataNode
  364. * @private
  365. */
  366. BuffaloReply._getType = function(dataNode) {
  367. return dataNode.tagName;
  368. }
  369. /**
  370. * Get the dataNode value. for cross browser use.
  371. * @private
  372. */
  373. BuffaloReply.getNodeText = function(dataNode) {
  374. if (dataNode.childNodes.length == 0) {
  375. return null;
  376. } else
  377. return dataNode.firstChild.nodeValue;
  378. }
  379. /**
  380. * @private
  381. */
  382. BuffaloReply.prototype.doBoolean = function (dataNode) {
  383. var value = BuffaloReply.getNodeText(dataNode);
  384. return (value == "1");
  385. }
  386. /**
  387. * @private
  388. */
  389. BuffaloReply.prototype.doDate = function (dataNode) {
  390. var dateStr = BuffaloReply.getNodeText(dataNode);
  391. //parseInt will be strange if the first char is '0', so set the radix.
  392. var year = parseInt(dateStr.substring(0,4),"10");
  393. var month = parseInt(dateStr.substring(4,6),"10") - 1;
  394. var day = parseInt(dateStr.substring(6,8),"10");
  395. var hour = parseInt(dateStr.substring(9,11),"10");
  396. var minute = parseInt(dateStr.substring(11,13),"10");
  397. var second = parseInt(dateStr.substring(13,15),"10");
  398. var d = new Date(year, month, day, hour, minute, second);
  399. return d;
  400. }
  401. /**
  402. * @private
  403. */
  404. BuffaloReply.prototype.doDouble = function (dataNode) {
  405. var value = BuffaloReply.getNodeText(dataNode);
  406. return parseFloat(value);
  407. }
  408. /**
  409. * @private
  410. */
  411. BuffaloReply.prototype.doInt = function (dataNode) {
  412. var value = BuffaloReply.getNodeText(dataNode);
  413. return parseInt(value);
  414. }
  415. /**
  416. * @private
  417. */
  418. BuffaloReply.prototype.doList = function (dataNode) {
  419. var arr = new Array();
  420. this._objects[this._objects.length] = arr;
  421. var children = dataNode.childNodes;
  422. for (var i=2; i < children.length; i++) {
  423. arr[arr.length] = this.deserialize(children[i]);
  424. }
  425. return arr;
  426. }
  427. /**
  428. * @private
  429. */
  430. BuffaloReply.prototype.doMap = function (dataNode) {
  431. var obj = new Object();
  432. this._objects[this._objects.length] = obj;
  433. var attrs = dataNode.childNodes;
  434. for (var i = 1; i < attrs.length; i+=2) {
  435. if (attrs[i+1].hasChildNodes() ) {
  436. obj[BuffaloReply.getNodeText(attrs[i])] = this.deserialize(attrs[i+1]);
  437. } else {
  438. obj[BuffaloReply.getNodeText(attrs[i])] = attrs[i+1].text;
  439. }
  440. }
  441. return obj;
  442. }
  443. /**
  444. * @private
  445. */
  446. BuffaloReply.prototype.doNull = function (dataNode) {
  447. return null;
  448. }
  449. /**
  450. * @private
  451. */
  452. BuffaloReply.prototype.doRef = function (dataNode) {
  453. var value = BuffaloReply.getNodeText(dataNode);
  454. var idx = parseInt(value);
  455. return this._objects[idx];
  456. }
  457. /**
  458. * @private
  459. */
  460. BuffaloReply.prototype.doString = function (dataNode) {
  461. var value = BuffaloReply.getNodeText(dataNode);
  462. if (value == null) {
  463. return "";
  464. }
  465. return (value);
  466. }
  467. /**
  468. * @private
  469. */
  470. BuffaloReply.prototype.doXML = function (dataNode) {
  471. var value = BuffaloReply.getNodeText(dataNode);
  472. return unescape(value);
  473. }
  474. /**
  475. * TODO: add Fault object.
  476. * @private
  477. */
  478. BuffaloReply.prototype.doFault = function (dataNode) {
  479. /*
  480. var value = BuffaloReply.getNodeText(dataNode);*/
  481. //TODO: need more attention.
  482. //return BuffaloReply.getNodeText(dataNode);
  483. var code = BuffaloReply.getNodeText(dataNode.childNodes[1]);
  484. var msg = BuffaloReply.getNodeText(dataNode.childNodes[3]);
  485. var detail = this.deserialize(dataNode.childNodes[5]);
  486. return new BuffaloFault(code, msg, detail);
  487. //return this.doMap(dataNode);
  488. }
  489. function BuffaloFault(code, message, detail) {
  490. this.code = code;
  491. this.message = message;
  492. this.detail = detail;
  493. this.toString = function() {
  494. return "code:" + this.code + ", message" + this.message + ", detail: " + this.detail;
  495. }
  496. }
  497. /**
  498. * The main entry class. User use like this:
  499. *
  500. * <pre class="code">
  501. * var buffalo = new Buffalo("/buffalo/BUFFALO");
  502. * buffalo.remoteCall("simpleService.divide", [1.0,2.0], function(reply) {
  503. * alert(reply.getResult());
  504. * }
  505. * );
  506. * </pre>
  507. * @param {String} gateway the gateway url.
  508. * @constructor
  509. */
  510. function Buffalo(gateway, async) {
  511. /**
  512. * The gate way.
  513. * @type String
  514. * @private
  515. */
  516. this.gateway = gateway;
  517. this.async = (async != null) ? async : true;
  518. this.onWaiting = Buffalo.showLoading;
  519. this.onFault = new Function();
  520. this.onError = new Function();
  521. }
  522. /**
  523. * Set the gateway(end point url) of this buffalo object.
  524. * The url can be absolute or relative, such as http://host:port/BUFFALO or /BUFFALO
  525. *
  526. * @param {String} gateway the gateway (end point url)
  527. *
  528. */
  529. Buffalo.prototype.setGateway = function(gateway) {
  530. this.gateway = gateway;
  531. }
  532. /**
  533. * Get the gate way of this buffalo object.
  534. * @type String
  535. * @returns the gateway of this buffalo object.
  536. */
  537. Buffalo.prototype.getGateway = function() {
  538. return this.gateway;
  539. }
  540. Buffalo.BOCLASS = "_BUFFALO_OBJECT_CLASS_";
  541. /**
  542. * The loading pane.
  543. * @type HTMLDOMElement
  544. * @private
  545. */
  546. Buffalo.loadingPane = null;
  547. /**
  548. * The exception pane
  549. * @type HTMLDOMElement
  550. * @private
  551. */
  552. Buffalo.exceptionPane = null;
  553. /**
  554. * the error pane
  555. * @type HTMLDOMElement
  556. * @private
  557. */
  558. Buffalo.errorPane = null;
  559. /**
  560. * Display or hide the loading pane.
  561. * You don't need to call this function directly. Buffalo will take care of it when
  562. * invoking remote functions.
  563. *
  564. * @param {boolean} state the state of the loading pane, if true, show it, otherwise hide it.
  565. */
  566. Buffalo.showLoading = function(state) {
  567. Buffalo.loadingPane = document.getElementById("buffalo_loading");
  568. if (Buffalo.loadingPane == null) {
  569. var el = document.createElement('DIV');
  570. el.setAttribute("id","buffalo_loading");
  571. el.style.cssText="display:none;font-family:Verdana;font-size:11px;border:1px solid #00CC00;background-color:#A4FFA4;padding:1px;position:absolute; right:1px; top:1px; width:110px; height:14px; z-index:1";
  572. el.innerHTML="Buffalo loading... ";
  573. document.body.appendChild(el);
  574. Buffalo.loadingPane = el;
  575. }
  576. if (state) {
  577. Buffalo.loadingPane.style.display="block";
  578. Buffalo.loadingPane.style.top = document.body.scrollTop+1;
  579. } else {
  580. Buffalo.loadingPane.style.display="none";
  581. }
  582. }
  583. /**
  584. * Display the exception pane.
  585. * TODO: not implemented yet.
  586. * @param {String} ex the exception string
  587. */
  588. Buffalo.showException = function(ex) {
  589. }
  590. /**
  591. * Hide the exception pane.
  592. * TODO: not implemented yet.
  593. *
  594. */
  595. Buffalo.hideException = function() {
  596. }
  597. Buffalo.instance = null;
  598. /**
  599. * Invoke the remote Call, innerMethod.
  600. *
  601. * @private
  602. * @param <String> url The end point of the remote call
  603. * @param <BurlapCall> burlapCall The burlap call object
  604. * @param <Function> callback if the call returns, invoke the callback function
  605. */
  606. Buffalo.prototype._remoteCall = function(url, burlapCall, callback) {
  607. Buffalo.instance = this;
  608. var xmlhttp = XmlHttp.create();
  609. xmlhttp.open("POST", url, this.async);
  610. xmlhttp.send(burlapCall.xml());
  611. //xmlhttp.onWaiting = this.onWaiting;
  612. // 异步方式
  613. if (this.async) {
  614. Buffalo.showLoading(true);
  615. //xmlhttp.onWaiting(true);
  616. //Buffalo.instance.onWaiting(true);
  617. xmlhttp.onreadystatechange = function() {
  618. if (xmlhttp.readyState == 4) {
  619. if (xmlhttp.status == '200') {
  620. var data = xmlhttp.responseText;
  621. //alert(data);
  622. // 标准的burlap返回的不是正常xml, 为了兼容普通burlap调用,需要进行调整
  623. if (data.indexOf("xmlns:burlap") == -1) {
  624. data.replace("<burlap:reply>", "<burlap:reply xmlns:burlap=\"http://www.amowa.net/buffalo/\">")
  625. }
  626. var reply = new BuffaloReply(data);
  627. Buffalo.showLoading(false);
  628. //Buffalo.instance.onWaiting(false);
  629. //xmlhttp.onWaiting(false);
  630. callback(reply);
  631. } else {
  632. var win = window.open("about:blank");
  633. win.document.open();
  634. win.document.write(xmlhttp.responseText);
  635. win.document.close();
  636. }
  637. }
  638. }
  639. } else { // 同步方式
  640. if (xmlhttp.status == '200') {
  641. var data = xmlhttp.responseText;
  642. // 标准的burlap返回的不是正常xml, 为了兼容普通burlap调用,需要进行调整
  643. if (data.indexOf("xmlns:burlap") == -1) {
  644. data.replace("<burlap:reply>", "<burlap:reply xmlns:burlap=\"http://www.amowa.net/buffalo/\">")
  645. }
  646. var reply = new BuffaloReply(data);
  647. callback(reply);
  648. } else {
  649. var win = window.open("about:blank");
  650. win.document.open();
  651. win.document.write(xmlhttp.responseText);
  652. win.document.close();
  653. }
  654. }
  655. }
  656. /**
  657. * Call like this: remoteCall("someService.someMethod", arrayOfParams, callbackFunction)
  658. *
  659. * @param <String> service string the service name, like someService.someMethod
  660. * @param <Array> params array the service call parameters
  661. * @param <Function> callback the call back function
  662. */
  663. Buffalo.prototype.remoteCall = function(service, params, callback) {
  664. var idx = service.indexOf(".");
  665. var serviceId = service.substring(0,idx);
  666. var method = service.substring(idx+1,service.length);
  667. var newUrl = this.gateway+"?sid="+serviceId;
  668. var call = new BuffaloCall(method);
  669. for (var i = 0; i < params.length; i++) {
  670. call.addParameter(params[i]);
  671. }
  672. this._remoteCall(newUrl, call, callback);
  673. }
  674. /**
  675. * Help method to get the element reference for the elementId.
  676. * for cross browser use.
  677. * @param {String} elementId the element id
  678. * @type HTMLDOMElement
  679. * @returns the dom element of the specified element id.
  680. */
  681. Buffalo.getElementById = function(elementId) {
  682. return document.getElementById(elementId);
  683. }