314n.org improver

Improves 314n.org user-expiriense.

目前为 2017-12-26 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name 314n.org improver
  3. // @name:ru 314n.org improver
  4. // @namespace 314n.org
  5. // @version 1.0.2
  6. // @match https://314n.org/*
  7. // @match https://314n.ru/*
  8. // @description Improves 314n.org user-expiriense.
  9. // @description:ru Улучшает взаимодействие с 314n.org.
  10. // @icon https://314n.org/f1.png
  11. // @require https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js
  12. // @run-at document-end
  13. // @license GPLv3
  14. // ==/UserScript==
  15.  
  16. /*jshint esnext: true */
  17.  
  18. const TEXT_COLOR_RGB = 'rgb(95, 191, 255)';
  19. const TEXT_COLOR_HEX = '#5FBFFF';
  20. const TEXT_HIGHLIGHTED_COLOR = '#eee';
  21. const EVENT_SUBMIT_ACCOUNT = 'event-submit-account';
  22. const CLASS_BOARD_LINK = 'board-link';
  23. const CLASS_THREAD_LINK = 'thread-link';
  24.  
  25. const CONTEXT_EMPTY = '';
  26. const CONTEXT_LOGGED = 'logged';
  27. const CONTEXT_BOARDS = 'boards';
  28. const CONTEXT_BOARD = 'board';
  29. const CONTEXT_TOPIC = 'topic';
  30.  
  31. var scriptElements = [];
  32. var loginForm;
  33. var regForm;
  34. var log = console.log;
  35. var ce = document.createElement.bind(document);
  36. var cn = document.createTextNode.bind(document);
  37. var boardEreg = /\[(\d+)\]\s+(.+)\s+/;
  38. var bracketsEreg = /\[(\d+)\]/;
  39. let underliner = (e)=>e.target.style.setProperty('text-decoration','underline');
  40. let unUnderliner = (e)=>e.target.style.removeProperty('text-decoration');
  41. let pointer = (e)=>e.target.style.cursor = 'pointer';
  42. let unPointer = (e)=>e.target.style.removeProperty('cursor');
  43. let textHighlight = (e)=>e.target.style.color = TEXT_HIGHLIGHTED_COLOR;
  44. let unTextHighlight = (e)=>e.target.style.removeProperty('color');
  45. var currentContext = '';
  46. let commandsMap = new Map(); /* String -> Command*/
  47. let checkCommandEReg = null;
  48. let lastEreg = /last/i;
  49. let lastPageNum = 9999;
  50.  
  51. $(document).ready(init);
  52.  
  53. function init(){
  54. initCommands();
  55. regForm = regEl(createRegForm());
  56. let reg = createPanelButton('reg', regForm.id);
  57. reg.addEventListener('click', showAccountForm);
  58. loginForm = regEl(createLoginForm());
  59. let login = createPanelButton('log-in', loginForm.id);
  60. login.addEventListener('click', showAccountForm);
  61. // create menu buttons wrapper
  62. let btnWrap = regEl(ce('div'));
  63. btnWrap.style.display = 'flex';
  64. btnWrap.style.setProperty('display','flex');
  65. btnWrap.style.setProperty('flex-flow','row nowrap');
  66. btnWrap.style.setProperty('justify-content','flex-start');
  67. btnWrap.style.position = 'absolute';
  68. btnWrap.style.bottom = '100%';
  69. btnWrap.style.right = '0';
  70. btnWrap.style.zIndex = '10';
  71. btnWrap.appendChild($(createPanelButton('boards')).click(e=>simulateInput('BOARDS')).get(0));
  72. btnWrap.appendChild(reg);
  73. btnWrap.appendChild(login);
  74. btnWrap.appendChild($(createPanelButton('log-out')).click(e => simulateInput('LOGOUT')).get(0));
  75. btnWrap.appendChild($(createPanelButton(' ? ')).click(e => simulateInput('HELP')).get(0));
  76. $('#board').append(btnWrap);
  77. $('#board').click(globalClick);
  78. reinitCmd();
  79. setTimeout(focusCmd, 1);
  80. currentContext = CONTEXT_EMPTY;
  81. }
  82.  
  83. function initCommands(){
  84. // no args
  85. addCommand(new CommandHelp());
  86. addCommand(new CommandBoards());
  87. addCommand(new Command('LOGOUT'));
  88. addCommand(new CommandNav('NEXT'));
  89. addCommand(new CommandNav('PREV'));
  90. addCommand(new CommandNav('FIRST'));
  91. addCommand(new CommandNav('LAST'));
  92. addCommand(new CommandNav('REFRESH'));
  93. // one arg
  94. addCommand(new CommandTimezone());
  95. addCommand(new CommandBoard());
  96. addCommand(new CommandRvt());
  97. addCommand(new CommandReply());
  98. addCommand(new CommandOneArg('DELETE','p'));
  99. addCommand(new CommandOneArg('EDIT','p'));
  100. addCommand(new CommandPage());
  101. // two args
  102. addCommand(new CommandAccount('LOGIN','u','p'));
  103. addCommand(new CommandAccount('REGISTER','u','p'));
  104. addCommand(new CommandTopic());
  105. ///NOTE No NEWTOPIC command - there is no simple way
  106. // to separate title from content without keys
  107. //construct ereg to match command name
  108. rebuildCommandsEReg();
  109. }
  110.  
  111. function addCommand(cmd,/*Bool*/rebuild){
  112. commandsMap.set(cmd.name,cmd);
  113. if(rebuild)
  114. rebuildCommandsEReg();
  115. }
  116.  
  117. function rebuildCommandsEReg(){
  118. let cmdsStr = '';
  119. commandsMap.forEach((val,key)=>{
  120. cmdsStr+= (key+'|');
  121. });
  122. cmdsStr = cmdsStr.substr(0, cmdsStr.length-1); // remove last | char from string
  123. checkCommandEReg = new RegExp(`^\\s*(${cmdsStr})`,'i');
  124. log(checkCommandEReg);
  125. }
  126.  
  127. function reinitCmd(){
  128. let cmd = el('#cmd');
  129. let newCmd = cmd.cloneNode();
  130. newCmd.dataset.new = 'yes';
  131. cmd.parentElement.appendChild(newCmd);
  132. $(cmd).remove();
  133. cmd = newCmd;
  134. $(cmd).keydown((e)=>{
  135. if (e.keyCode == 38) {
  136. if (command_number > 0) {
  137. if (command_number == commands.length)
  138. commands.push(e.currentTarget.value);
  139. command_number--;
  140. e.currentTarget.value = commands[command_number];
  141. }
  142. return false;
  143. }
  144.  
  145. if (e.keyCode == 40) {
  146. if (command_number < commands.length - 1) {
  147. command_number++;
  148. e.currentTarget.value = commands[command_number];
  149. }
  150. return false;
  151. }
  152. if((e.keyCode == 13 || e.key=='Enter' || e.code=='Enter') && !e.shiftKey){
  153. let command = getCommandObj(cmd.value);
  154. logInput(cmd.value);
  155. sendCommand(command.processInput(cmd.value), command.processOutput.bind(command));
  156. return false;
  157. }
  158. });
  159. return cmd;
  160. }
  161.  
  162. function getCommandObj(input){
  163. let match = checkCommandEReg.exec(input);
  164. if(match!==null){
  165. let cmd = commandsMap.get(match[1].toLowerCase());
  166. if(cmd) return cmd;
  167. }
  168. return new Command(input);
  169. }
  170.  
  171. function globalClick(e){
  172. if(e.target.classList.contains(CLASS_BOARD_LINK)){
  173. simulateInput(`BOARD -n ${e.target.dataset.boardNumber}`);
  174. }
  175. else if(e.target.classList.contains(CLASS_THREAD_LINK)){
  176. simulateInput(`TOPIC -n ${e.target.dataset.threadNumber}`);
  177. }
  178. }
  179.  
  180. function createLoginForm(){
  181. return createAccountForm('LOGIN');
  182. }
  183.  
  184. function createRegForm(){
  185. let form = createAccountForm('REGISTER');
  186. form.addEventListener(EVENT_SUBMIT_ACCOUNT,(e)=>{
  187. let login = id('login-form');
  188. let reg = e.currentTarget;
  189. if(login!==null){
  190. let lname = el('[type=text]',login);
  191. let lpass = el('[type=password]',login);
  192. let rname = el('[type=text]',reg);
  193. let rpass = el('[type=password]',reg);
  194. lname.value = rname.value;
  195. lname.innerText = rname.innerText;
  196. lpass.value = rpass.value;
  197. lpass.innerText = rpass.innerText;
  198. }
  199. });
  200. return form;
  201. }
  202.  
  203. function createAccountForm(commandText){
  204. let form = ce('div');
  205. function getInput(type, name){
  206. var inp = ce('input');
  207. inp.setAttribute('type',type);
  208. inp.setAttribute('name',name);
  209. sanitizeInputStyle(inp);
  210. inp.style.color = TEXT_COLOR_HEX;
  211. inp.style.paddingBottom = '2px';
  212. inp.style.borderBottom = `2px solid ${TEXT_COLOR_HEX}`;
  213. inp.style.width = '10em';
  214. return inp;
  215. }
  216. let nameInput = getInput('text','name');
  217. let nameLabel = ce('label');
  218. nameLabel.appendChild(createReverse('name: '));
  219. nameLabel.appendChild(nameInput);
  220. let passInput = getInput('password','pass');
  221. let passLabel = ce('label');
  222. passLabel.appendChild(createReverse('password: '));
  223. passLabel.appendChild(passInput);
  224. let label = createReverse(`[ ${commandText.toUpperCase()} ]`);
  225. label.style.outline='none';
  226. let ok = ce('button');
  227. ok.appendChild(label);
  228. ok.style.margin = '0 auto';
  229. ok.style.marginTop = '15px';
  230. ok.style.color = TEXT_COLOR_HEX;
  231. ok.style.display = 'block';
  232. sanitizeInputStyle(ok);
  233. $(ok).hover((e)=>{
  234. e.currentTarget.querySelector('span').style.backgroundColor = '#eee';
  235. ok.style.cursor = 'pointer';
  236. }, (e)=>{
  237. e.currentTarget.querySelector('span').style.removeProperty('background-color');
  238. ok.style.removeProperty('cursor');
  239. });
  240. function submit(e){
  241. let name = el('[type=text]',form);
  242. let pass = el('[type=password]',form);
  243. simulateInput(`${commandText.toLowerCase()} -u ${name.value} -p ${pass.value}`);
  244. form.style.display = 'none';
  245. form.dispatchEvent(new Event(EVENT_SUBMIT_ACCOUNT));
  246. }
  247. ok.addEventListener('click',submit);
  248. passInput.addEventListener('keydown',(evt)=>{
  249. if(evt.keyCode===13)
  250. submit();
  251. });
  252. form.id = `${commandText.toLowerCase()}-form`;
  253. form.classList.add('acc-form');
  254. form.style.outline = '1px solid rgb(0,255,255)';
  255. form.style.padding = '15px';
  256. form.style.position = 'absolute';
  257. form.style.top = '0';
  258. form.style.right = '0';
  259. form.style.textAlign = 'right';
  260. form.style.backgroundColor = '#000';
  261. form.style.display = 'none';
  262. form.appendChild(nameLabel);
  263. form.appendChild(ce('br'));
  264. form.appendChild(passLabel);
  265. form.appendChild(ce('br'));
  266. form.appendChild(ok);
  267. id('board').appendChild(form);
  268. return form;
  269. }
  270.  
  271. function sanitizeInputStyle(el){
  272. el.style.outline = 'none';
  273. el.style.border = 'none';
  274. el.style.background = 'transparent';
  275. return el;
  276. }
  277.  
  278. function createPanelButton(text, forId){
  279. let ret = createReverse(text);
  280. $(ret).hover((e)=>{ret.style.cursor='pointer';
  281. ret.style.backgroundColor='#eee';},
  282. (e)=>{ret.style.cursor='initial';
  283. ret.style.removeProperty('background-color')});
  284. if(forId)
  285. ret.dataset.forId = forId;
  286. return ret;
  287. }
  288.  
  289. function createReverse(text){
  290. var ret = ce('span');
  291. ret.classList.add('reverse');
  292. ret.style.padding = '2px 4px';
  293. ret.style.marginRight = '5px';
  294. ret.innerText = text;
  295. return ret;
  296. }
  297.  
  298. function regEl(el){
  299. scriptElements.push(el);
  300. return el;
  301. }
  302.  
  303. function removeRegistered(){
  304. scriptElements.forEach(el=>{
  305. $(el).remove();
  306. });
  307. scriptElements = [];
  308. }
  309.  
  310. function simulateInput(command){
  311. let cmd = el('#cmd');
  312. cmd.value = command;
  313. cmd.innerText = command;
  314. cmd.dispatchEvent(new KeyboardEvent('keydown',{keyCode:13, shiftKey:false}));
  315. }
  316.  
  317. function showAccountForm(e){
  318. let form = id(e.currentTarget.dataset.forId);
  319. if(form){
  320. if(form.parentElement===null || form.style.display === 'none'){
  321. let board = id('board');
  322. els('.acc-form',board).forEach((elt)=>elt.style.display='none');
  323. board.appendChild(form);
  324. form.style.display = 'block';
  325. }else{
  326. form.style.display = 'none';
  327. }
  328. }
  329. }
  330.  
  331. function logInput(/*String*/command){
  332. commands.push(command);
  333. command_number = commands.length;
  334. }
  335.  
  336. function sendCommand(/*String*/command,/*Function*/callback){
  337. el('#cmd').value = '';
  338. el('#cmd').innerText = '';
  339. $.ajax({
  340. type:'POST',
  341. url:'console.php',
  342. dataType:'json',
  343. data:{input: command},
  344. success: callback
  345. // success: (r)=>{callback(r);}
  346. });
  347. }
  348.  
  349. function focusCmd(){
  350. el('#cmd').focus();
  351. }
  352.  
  353. function removeEl(from,selector){
  354. var els = from.querySelectorAll(selector);
  355. els.forEach((v,i,l)=>{
  356. if(v.parentElement!==null)
  357. v.parentElement.removeChild(v);
  358. })
  359. }
  360.  
  361. function id(id){
  362. return document.getElementById(id);
  363. }
  364.  
  365. function el(/*String*/selector,/*Element*/el){
  366. if(el) return el.querySelector(selector);
  367. else return document.querySelector(selector);
  368. }
  369.  
  370. function els(/*String*/selector,/*Element*/el){
  371. if(el) return el.querySelectorAll(selector);
  372. else return document.querySelectorAll(selector);
  373. }
  374.  
  375. function loading(onComplete){
  376. str = 'Loading...';
  377. nextchar = str.charAt($('#loading').html().length);
  378. if ($('#loading').html().length < 10) {
  379. $('#loading').html($('#loading').html()+nextchar);
  380. if(onComplete)
  381. setTimeout(loading, 40, onComplete);
  382. else
  383. setTimeout(loading, 40);
  384. } else {
  385. $('.content').css('display', 'block');
  386. if(onComplete)
  387. onComplete();
  388. else
  389. nav_down();
  390. }
  391. }
  392.  
  393. function empty(){}
  394.  
  395. //---------------------------------------------------
  396. // COMMANDS
  397. //---------------------------------------------------
  398. /*
  399. NOTE How commands works.
  400. There is two ways - WITH keys and WITHOUT keys.
  401. If input has at least one key like '-k'
  402. then it passes to server without any changes.
  403. Otherwise there is an attempt to extract values
  404. and rebuild input with concrete key-value data,
  405. then new input passed to server.
  406. Otherwise input passes to server without any changes.
  407. */
  408.  
  409. /** Base command */
  410. function Command(name){
  411. this.name = name?name:'';
  412. this.name = this.name.toLowerCase();
  413. this.argReg = /[^\\]-(.+?)(?= -|$)/i; // is need only test, so no GLOBAL flag
  414. }
  415. Command.prototype.processInput = function(input){return input;};
  416. Command.prototype.processOutput = function(response){
  417. if (response.edit) {
  418. $('#path').html(response.path+'&nbsp;>&nbsp;');
  419. $('#cmd').val(response.edittext);
  420. } else {
  421. if (response.clear) $('#content').html('');
  422. $('#content').append(response.message);
  423. if (response.path) $('#path').html(response.path+'&nbsp;>&nbsp;');
  424. $('.content').css('display', 'block');
  425. if (response.clear) loading();
  426. else nav_down();
  427. }
  428. focusCmd();
  429. };
  430. Command.processOutputWithContext = function(response){
  431. switch(currentContext){
  432. case CONTEXT_BOARD:
  433. // log('board context');
  434. commandsMap.get('board').processOutput(response);
  435. break;
  436. case CONTEXT_TOPIC:
  437. // log('topic context');
  438. commandsMap.get('topic').processOutput(response);
  439. break;
  440. default:
  441. // log('no ctx');
  442. Object.getPrototypeOf(Object.getPrototypeOf(this)).processOutput(response);
  443. }
  444. };
  445. Command.getLastPage = function(pageStr){
  446. return lastEreg.test(pageStr)?lastPageNum:pageStr;
  447. };
  448.  
  449. //---------------------------------------------------
  450. // NO arg commands
  451. //---------------------------------------------------
  452.  
  453. function CommandHelp(){
  454. Command.call(this, 'help');
  455. this.boardReg = /(BOARD +)(-n)/;
  456. this.topicReg = /TOPIC -n <number> [-p <page>]/;
  457. this.keysReg = /Before the parameter.+\./;
  458. this.newKeysInfo = 'You can write commands* with** or without** keys (keys looks like "-k").<br><br>* with the exception of <span class=reverse style="padding:0 4px"> NEWTOPIC </span><br>** you cannot combine both ways - it is possible to use only one at a time';
  459. }
  460. CommandHelp.prototype = Object.create(Command.prototype);
  461. CommandHelp.prototype.constructor = CommandHelp;
  462. CommandHelp.prototype.processInput = function(input){return input;};
  463. CommandHelp.prototype.processOutput = function(response){
  464. if(response.clear) $('#content').html('');
  465. let msg = response.message.replace(this.keysReg, this.newKeysInfo);
  466. $('#content').append(msg);
  467. if (response.path) $('#path').html(response.path+'&nbsp;>&nbsp;');
  468. if (response.clear) loading();
  469. else nav_down();
  470. };
  471.  
  472. function CommandBoards(){
  473. Command.call(this,'boards');
  474. }
  475. CommandBoards.prototype = Object.create(Command.prototype);
  476. CommandBoards.prototype.constructor = CommandBoards;
  477. CommandBoards.prototype.processOutput = function(response){
  478. if (response.clear) $('#content').html('');
  479. let els = $.parseHTML(response.message);
  480. els.forEach((el)=>{
  481. let nodes = Array.prototype.slice.call(el.childNodes);
  482. nodes = nodes.map((n)=>{
  483. if(n.nodeType!==3)
  484. return n;
  485. else{
  486. let matches = boardEreg.exec(n.textContent);
  487. if(matches!==null){
  488. let num = matches[1];
  489. let name = matches[2];
  490. let b = ce('span');
  491. b.classList.add(CLASS_BOARD_LINK);
  492. b.innerText = `[${num}] ${name} `;
  493. b.dataset.boardNumber = num;
  494. $(b).hover(underliner,unUnderliner);
  495. $(b).hover(pointer,unPointer);
  496. $(b).hover(textHighlight,unTextHighlight);
  497. return b;
  498. }
  499. else return n;
  500. }
  501. });
  502. while(el.firstChild!==null)
  503. el.removeChild(el.firstChild);
  504. nodes.forEach(n=>el.appendChild(n));
  505. });
  506. els.forEach((el)=>$('#content').append(el));
  507. if (response.path) $('#path').html(response.path+'&nbsp;>&nbsp;');
  508. if (response.clear) loading();
  509. else nav_down();
  510. focusCmd();
  511. currentContext = CONTEXT_BOARDS;
  512. };
  513.  
  514. function CommandNav(name){
  515. Command.call(this, name);
  516. }
  517. CommandNav.prototype = Object.create(Command.prototype);
  518. CommandNav.prototype.constructor = CommandNav;
  519. CommandNav.prototype.processOutput = function(response){
  520. Command.processOutputWithContext.call(this,response);
  521. };
  522.  
  523. //---------------------------------------------------
  524. // ONE args commands
  525. //---------------------------------------------------
  526.  
  527. function CommandOneArg(name,arg){
  528. Command.call(this, name);
  529. this.arg = arg;
  530. this.ereg = new RegExp(`${this.name} +(.+)`,'i');
  531. }
  532. CommandOneArg.prototype = Object.create(Command.prototype);
  533. CommandOneArg.prototype.constructor = CommandOneArg;
  534. CommandOneArg.prototype.processInput = function(input){
  535. let match = this.argReg.exec(input);
  536. if(match){
  537. return input;
  538. }
  539. match = this.ereg.exec(input);
  540. if(match){
  541. return `${this.name} -${this.arg} ${match[1]}`;
  542. }
  543. return input;
  544. };
  545.  
  546. function CommandTimezone(){
  547. CommandOneArg.call(this, 'timezone', 'u');
  548. }
  549. CommandTimezone.prototype = Object.create(CommandOneArg.prototype);
  550. CommandTimezone.prototype.constructor = CommandTimezone;
  551.  
  552. function CommandBoard(){
  553. CommandOneArg.call(this,'board', 'n');
  554. }
  555. CommandBoard.prototype = Object.create(CommandOneArg.prototype);
  556. CommandBoard.prototype.constructor = CommandBoard;
  557. CommandBoard.prototype.processOutput = function(response){
  558. if (response.clear) $('#content').html('');
  559. let wrap = ce('div');
  560. let els = $.parseHTML(response.message);
  561. els.forEach((elt)=>wrap.appendChild(elt));
  562. let numSelector = 'tr > td.postsnumber';
  563. let nameSelector = 'td > span.reverse';
  564. let nums = wrap.querySelectorAll(numSelector);
  565. let names = wrap.querySelectorAll(nameSelector);
  566. nums.forEach((elt,i)=>{
  567. let matches = bracketsEreg.exec(elt.innerText);
  568. let threadNumber = matches[1];
  569. let span = ce('span');
  570. span.classList.add(CLASS_THREAD_LINK);
  571. span.innerText = threadNumber;
  572. span.dataset.threadNumber = threadNumber;
  573. $(span).hover(underliner, unUnderliner);
  574. $(span).hover(pointer, unPointer);
  575. $(span).hover(textHighlight, unTextHighlight);
  576. elt.innerText = '';
  577. elt.appendChild(cn('['));
  578. elt.appendChild(span);
  579. elt.appendChild(cn(']'));
  580. let nameElt = names[i];
  581. nameElt.classList.add(CLASS_THREAD_LINK);
  582. nameElt.dataset.threadNumber = threadNumber;
  583. $(nameElt).hover(pointer, unPointer);
  584. $(nameElt).hover((e)=>e.currentTarget.style.backgroundColor='#eee',
  585. (e)=>e.currentTarget.style.removeProperty('background-color'));
  586. });
  587. els.forEach((elt)=>el('#content').appendChild(elt));
  588. if (response.path) $('#path').html(response.path+'&nbsp;>&nbsp;');
  589. if (response.clear) loading(empty);
  590. focusCmd();
  591. currentContext = CONTEXT_BOARD;
  592. };
  593.  
  594. function CommandRvt(){
  595. CommandOneArg.call(this,'rvt','p');
  596. this.ereg = new RegExp(`${this.name}( +(\\w+))?`,'i');
  597. }
  598. CommandRvt.prototype = Object.create(CommandOneArg.prototype);
  599. CommandRvt.prototype.constructor = CommandRvt;
  600. CommandRvt.prototype.processInput = function(input){
  601. let match = this.argReg.exec(input);
  602. if(match)
  603. return input;
  604. match = this.ereg.exec(input);
  605. if(match){
  606. let page = match[1];
  607. let ret;
  608. if(page){
  609. page = Command.getLastPage(match[2]);
  610. ret = `rvt -p ${page}`;
  611. }else
  612. ret = `rvt`;
  613. return ret;
  614. }
  615. return ret;
  616. };
  617. CommandRvt.prototype.processOutput = CommandBoard.prototype.processOutput;
  618.  
  619. function CommandReply(){
  620. CommandOneArg.call(this,'reply','m');
  621. this.argReg = /[^\\]-(\w)(?= |$)/i;
  622. }
  623. CommandReply.prototype = Object.create(CommandOneArg.prototype);
  624. CommandReply.prototype.constructor = CommandReply;
  625.  
  626. function CommandPage(){
  627. CommandOneArg.call(this,'page','p');
  628. }
  629. CommandPage.prototype = Object.create(CommandOneArg.prototype);
  630. CommandPage.prototype.constructor = CommandPage;
  631. CommandPage.prototype.processOutput = function(r){
  632. Command.processOutputWithContext.call(this, r);
  633. };
  634.  
  635. //---------------------------------------------------
  636. // TWO args commands
  637. //---------------------------------------------------
  638.  
  639. function CommandTwoArgs(name,arg1,arg2){
  640. CommandOneArg.call(this,name,arg1);
  641. this.arg2 = arg2;
  642. this.ereg = new RegExp(`${this.name} +(\\w+) +(.+)`,'i');
  643. }
  644. CommandTwoArgs.prototype = Object.create(CommandOneArg.prototype);
  645. CommandTwoArgs.prototype.constructor = CommandTwoArgs;
  646. CommandTwoArgs.prototype.processInput = function(input){
  647. // check if input has key-value like '-u username'
  648. // if so do nothing and return input as is
  649. // otherwise check if input have no keys like 'login username password'
  650. // if so - build command with appropriate keys and values
  651. // else return input as is
  652. let match = this.argReg.exec(input);
  653. if(match){
  654. // it is a key-value variant
  655. return input;
  656. }
  657. match = this.ereg.exec(input);
  658. if(match){
  659. // no keys variant
  660. return `${this.name} -${this.arg} ${match[1]} -${this.arg2} ${match[2]}`;
  661. }
  662. return input;
  663. };
  664.  
  665. function CommandAccount(name, arg1, arg2){
  666. CommandTwoArgs.call(this,name,arg1,arg2);
  667. }
  668. CommandAccount.prototype = Object.create(CommandTwoArgs.prototype);
  669. CommandAccount.prototype.constructor = CommandAccount;
  670.  
  671. function CommandTopic(){
  672. CommandTwoArgs.call(this,'topic','n','p');
  673. this.ereg = new RegExp(`${this.name} +(\\w+)( +(\\w+))?`,'i');
  674. }
  675. CommandTopic.prototype = Object.create(CommandTwoArgs.prototype);
  676. CommandTopic.prototype.constructor = CommandTopic;
  677. CommandTopic.prototype.processInput = function(input){
  678. let match = this.argReg.exec(input);
  679. if(match)
  680. return input;
  681. match = this.ereg.exec(input);
  682. if(match){
  683. let num = match[1];
  684. let page = match[2];
  685. let ret;
  686. if(page){
  687. page = Command.getLastPage(match[3]);
  688. ret = `${this.name} -n ${num} -p ${page}`;
  689. }else{
  690. ret = `${this.name} -n ${num}`;
  691. }
  692. return ret;
  693. }
  694. return input;
  695. };
  696. CommandTopic.prototype.processOutput = function(response){
  697. Object.getPrototypeOf(CommandTopic.prototype).processOutput.call(this, response);
  698. currentContext = CONTEXT_TOPIC;
  699. };
  700.  
  701.  
  702.  
  703.  
  704.  
  705.  
  706.  
  707.  
  708.  
  709.  
  710.  
  711.  
  712.  
  713.  
  714.  
  715.  
  716.  
  717.  
  718.  
  719.