mark-control.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. function MarkControl(option) {
  2. this.option = option;
  3. this.maxPrefetchCount = parseInt(option.prefetchCount);
  4. this.maxPrefetchCount = this.maxPrefetchCount != undefined && this.maxPrefetchCount > 2 ? this.maxPrefetchCount : 2;
  5. this.container = option.container;
  6. this.context = {
  7. imageServer: option.imageServer,
  8. staticServer: option.staticServer,
  9. isFinish: false,
  10. prefetching: false,
  11. prefetchTask: []
  12. };
  13. // 初始化容器结构
  14. this.initContainer();
  15. // 初始化事件监听
  16. this.initTriggers(option);
  17. // 初始化功能模块
  18. this.initModules(option);
  19. // 初始化成功回调方法
  20. // console.log('MarkControl init success!');
  21. // if (option.success != undefined && typeof(option.success) == 'function')
  22. // {
  23. // option.success();
  24. // }
  25. }
  26. MarkControl.prototype.initContainer = function() {
  27. var height = this.option.height;
  28. if (height == undefined) {
  29. height = $(window).height();
  30. }
  31. this.container = getDom(this.main_row_dom, this).appendTo(this.container);
  32. if (this.option.enableSidear != false) {
  33. this.container.sidebar = getDom(this.sidebar_dom, this).appendTo(this.container);
  34. this.container.sidebar.css('max-height', height);
  35. }
  36. this.container.center = getDom(this.center_dom, this).appendTo(this.container);
  37. this.container.header = getDom(this.center_header_dom, this).appendTo(this.container.center).find('.header');
  38. if(this.option.switchCommonUrl!=undefined && this.option.switchCommonUrl.length>0){
  39. var switchButton = this.container.header.find('#switch-common-button');
  40. switchButton.attr('href', this.option.switchCommonUrl);
  41. switchButton.show();
  42. }
  43. this.container.centerContainer = getDom(this.center_content_dom, this).appendTo(this.container.center);
  44. this.container.centerContent = this.container.centerContainer.find('.image-content');
  45. this.container.centerNavbar = this.container.centerContent.find('nav');
  46. this.container.centerList = [];
  47. this.navNumber = 0;
  48. this.container.height(height);
  49. this.container.centerContent.css('height', height - this.container.header.parent().height());
  50. this.initHeaderAndAssistant();
  51. }
  52. MarkControl.prototype.initHeaderAndAssistant = function() {
  53. var self = this;
  54. this.container.header.find('#mark-user-name').html(this.option.userName);
  55. if (this.option.logoutTitle != undefined) {
  56. this.container.header.find('#logout-title').html(this.option.logoutTitle);
  57. }
  58. this.container.header.find('#logout-link').click(function() {
  59. self.trigger('logout.link.click');
  60. return true;
  61. })
  62. this.container.assistant = getDom(this.assistant_dom, this).appendTo(this.container);
  63. this.container.assistant.positionSet = false;
  64. this.container.assistantButton = this.container.header.find('#assistant-button');
  65. this.container.assistantButton.click(this, function(event) {
  66. if (self.container.assistant.positionSet == false) {
  67. self.container.assistant.offset({
  68. top: self.container.assistantButton.position().top + self.container.assistantButton.height() + 5,
  69. left: self.container.assistantButton.position().left - 85
  70. });
  71. self.container.assistant.positionSet = true;
  72. }
  73. self.container.assistant.toggle();
  74. });
  75. }
  76. MarkControl.prototype.initMarkFunction = function() {
  77. var functionList = this.container.assistant.functionList;
  78. if (functionList == undefined) {
  79. functionList = getDom(this.mark_function_dom, this).appendTo(this.container.assistant).find('#function-list');
  80. this.container.assistant.functionList = functionList;
  81. }
  82. }
  83. MarkControl.prototype.addNavGroup = function(title, content){
  84. var self = this;
  85. self.navNumber++;
  86. var nav = $('<a href="#"><span>'+title+'</span></a>').appendTo(self.container.centerNavbar);
  87. nav.attr('data-number', self.navNumber);
  88. content.attr('data-number', self.navNumber);
  89. nav.click(function(){
  90. self.container.centerNavbar.find('a').removeClass('selected');
  91. $(this).addClass('selected');
  92. for(var i in self.container.centerList){
  93. var dom = self.container.centerList[i];
  94. if(dom.attr('data-number')==$(this).attr('data-number')){
  95. dom.show();
  96. }else{
  97. dom.hide();
  98. }
  99. }
  100. });
  101. self.container.centerList.push(content);
  102. return nav;
  103. }
  104. // 增加某个事件的监听方法
  105. MarkControl.prototype.on = function(eventName, caller, callback, async) {
  106. if (eventName && callback && eventName.length > 0 && typeof(callback) == 'function') {
  107. if (async) {
  108. this.container.bind(eventName, callback);
  109. } else {
  110. if (this.triggers[eventName] == undefined) {
  111. this.triggers[eventName] = new Array();
  112. }
  113. this.triggers[eventName].push({
  114. caller: caller,
  115. callback: callback
  116. });
  117. }
  118. }
  119. }
  120. // 触发某个事件,并传递事件相关内容
  121. MarkControl.prototype.trigger = function(eventName, eventObject) {
  122. var result = true;
  123. if (eventName && eventName.length > 0) {
  124. var array = this.triggers[eventName];
  125. if (array != undefined && array.length > 0) {
  126. var event = {
  127. name: eventName
  128. }
  129. for (var i in array) {
  130. result = result & array[i].callback.call(array[i].caller, event, this.context, eventObject);
  131. }
  132. }
  133. this.container.trigger(eventName, this.context, eventObject);
  134. }
  135. return result;
  136. }
  137. // 初始化事件监听
  138. MarkControl.prototype.initTriggers = function(option) {
  139. if (this.triggers == undefined) {
  140. this.triggers = {};
  141. }
  142. if (option != undefined && option.on != undefined) {
  143. for (var name in option.on) {
  144. this.on(name, option.on[name]);
  145. }
  146. }
  147. var self = this;
  148. this.on('mark.sidebar.open', this, function(event, context, eventObject) {
  149. this.container.assistant.hide();
  150. if (this.container.center.hasClass('span12')) {
  151. this.container.center.removeClass('span12');
  152. this.container.center.addClass('span10');
  153. } else if (this.container.center.hasClass('span7')) {
  154. this.container.center.removeClass('span7');
  155. this.container.center.addClass('span5');
  156. }
  157. this.trigger('center.width.change');
  158. });
  159. this.on('mark.sidebar.close', this, function(event, context, eventObject) {
  160. this.container.assistant.hide();
  161. if (this.container.center.hasClass('span10')) {
  162. this.container.center.removeClass('span10');
  163. this.container.center.addClass('span12');
  164. } else if (this.container.center.hasClass('span5')) {
  165. this.container.center.removeClass('span5');
  166. this.container.center.addClass('span7');
  167. }
  168. this.trigger('center.width.change');
  169. });
  170. this.on('task.load.finish', this, function(event, context, eventObject) {
  171. self.container.centerNavbar.find('a:first').trigger('click');
  172. });
  173. this.on('task.get.finish', this, function(event, context, eventObject) {
  174. context.prefetchCallback = undefined;
  175. });
  176. this.on('task.get.none', this, function(event, context, eventObject) {
  177. self.getStatus();
  178. if (context.task == undefined && self.option.clearUrl != undefined) {
  179. $.post(self.option.clearUrl, {}, function() {});
  180. }
  181. context.prefetchCallback = function() {
  182. context.prefetchCallback = undefined;
  183. if (self.context.task == undefined && self.context.prefetchTask.length > 0) {
  184. self.getTask();
  185. }
  186. }
  187. });
  188. this.on('task.prefetch.success', this, function(event, context, eventObject) {
  189. if (context.prefetchCallback != undefined) {
  190. context.prefetchCallback();
  191. }
  192. setTimeout(function() {
  193. self.prefetch();
  194. }, 500);
  195. });
  196. this.on('task.prefetch.error', this, function(event, context, eventObject) {
  197. setTimeout(function() {
  198. self.prefetch();
  199. }, 500);
  200. });
  201. this.on('task.prefetch.none', this, function(event, context, eventObject) {
  202. if (context.prefetchCallback != undefined) {
  203. context.prefetchCallback();
  204. }
  205. if (context.isFinish != true) {
  206. setTimeout(function() {
  207. self.prefetch();
  208. }, 1000);
  209. }
  210. });
  211. this.on('task.prefetch.finish', this, function(event, context, eventObject) {
  212. self.getTask();
  213. });
  214. this.on('task.submit.before', this, function(event, context, eventObject) {
  215. context.submitting = true;
  216. });
  217. this.on('task.submit.success', this, function(event, context, eventObject) {
  218. context.submitting = false;
  219. context.task = undefined;
  220. self.getTask();
  221. });
  222. this.on('task.submit.error', this, function(event, context, eventObject) {
  223. context.submitting = false;
  224. });
  225. this.on('task.pass.success', this, function(event, context, eventObject) {
  226. if (context.task != undefined && self.option.clearUrl != undefined) {
  227. $.post(self.option.clearUrl, {
  228. libraryId: context.task.libraryId
  229. });
  230. }
  231. context.task = undefined;
  232. self.getTask();
  233. });
  234. this.on('task.load.finish', this, function(event, context, eventObject) {
  235. var timestamp = new Date().getTime();
  236. context.task.spent = timestamp;
  237. });
  238. $(document).keypress(this, function(event) {
  239. if (self.context.listenKeyboard != false) {
  240. return self.trigger('key.press', event);
  241. }
  242. });
  243. $(document).keydown(this, function(event) {
  244. if (self.context.listenKeyboard != false) {
  245. return self.trigger('key.down', event);
  246. }
  247. });
  248. $(document).keyup(this, function(event) {
  249. if (self.context.listenKeyboard != false) {
  250. return self.trigger('key.up', event);
  251. }
  252. });
  253. window.onbeforeunload = function(e) {
  254. if (self.option.clearUrl != undefined) {
  255. $.post(self.option.clearUrl);
  256. }
  257. }
  258. }
  259. // 初始化功能模块
  260. MarkControl.prototype.initModules = function(option) {
  261. if (this.modules == undefined) {
  262. this.modules = {};
  263. }
  264. var names = [];
  265. var options = [];
  266. for (var name in this.defaultModules) {
  267. names.push(name);
  268. options[name] = this.defaultModules[name];
  269. }
  270. if (option.modules != undefined) {
  271. for (var name in option.modules) {
  272. if (options[name] == undefined) {
  273. names.push(name);
  274. options[name] = {};
  275. }
  276. $.extend(options[name], option.modules[name]);
  277. }
  278. }
  279. this.initModule(names, options, this.option.success);
  280. // initModule(this, names, 0, options);
  281. }
  282. // 指定初始化某个名称的模块
  283. MarkControl.prototype.initModule = function(names, options, success) {
  284. for (var i in names) {
  285. var name = names[i];
  286. var option = options[name];
  287. var moduleInit = name.replace(/-/g, '_');
  288. if (option == undefined || typeof(option) != 'object') {
  289. option = {};
  290. }
  291. option.markControl = this;
  292. eval('this.modules[name]=' + moduleInit + '(option, function(){})');
  293. }
  294. if (success != undefined && typeof(success) == 'function') {
  295. success();
  296. }
  297. }
  298. function initModuleAsync(markControl, names, index, option) {
  299. if (index < names.length) {
  300. var name = names[index];
  301. var moduleOption = option[name];
  302. var moduleUrl = 'modules/' + name + '.js';
  303. var moduleInit = name.replace(/-/g, '_');
  304. var modules = markControl.modules;
  305. if (modules[name] == undefined) {
  306. if (typeof(moduleOption) != 'object') {
  307. moduleOption = {};
  308. }
  309. moduleOption.markControl = markControl;
  310. $.getScript(moduleUrl, function() {
  311. var success = function() {
  312. initModule(markControl, names, index + 1, option);
  313. }
  314. eval('modules[name]=' + moduleInit + '(moduleOption, success)');
  315. });
  316. } else {
  317. initModule(markControl, names, index + 1, option);
  318. }
  319. } else {
  320. if (markControl.option.success != undefined && typeof(markControl.option.success) == 'function') {
  321. markControl.option.success();
  322. }
  323. }
  324. }
  325. MarkControl.prototype.start = function(taskOption) {
  326. taskOption.markControl = this;
  327. var markControl = this;
  328. taskOption.success = function() {
  329. markControl.context.prefetchCallback = function() {
  330. markControl.context.prefetchCallback = undefined;
  331. markControl.getTask();
  332. }
  333. markControl.context.statusCallback = function() {
  334. markControl.context.statusCallback = undefined;
  335. markControl.prefetch();
  336. }
  337. markControl.getStatus();
  338. };
  339. taskOption.error = function(message) {
  340. alert('初始化失败,请刷新页面重新加载');
  341. };
  342. this.taskControl = new TaskControl(taskOption);
  343. this.taskControl.init();
  344. }
  345. // task预加载
  346. MarkControl.prototype.prefetch = function() {
  347. var taskControl = this.taskControl;
  348. var markControl = this;
  349. var context = this.context;
  350. var imageBuilder = this.modules['image-builder'];
  351. if (context.isFinish != true) {
  352. if (taskControl.isFinish()) {
  353. context.isFinish = true;
  354. } else if (context.prefetchTask.length >= markControl.maxPrefetchCount) {
  355. markControl.trigger('task.prefetch.success');
  356. } else if (context.prefetching == false) {
  357. context.prefetching = true;
  358. markControl.trigger('task.prefetch.before');
  359. taskControl.fetch(function(task) {
  360. if (imageBuilder != undefined) {
  361. imageBuilder.build(task, function(error) {
  362. if (error) {
  363. context.prefetching = false;
  364. markControl.trigger('task.prefetch.error');
  365. } else {
  366. context.prefetchTask.push(task);
  367. context.prefetchStatus = undefined;
  368. context.prefetching = false;
  369. markControl.trigger('task.prefetch.success');
  370. }
  371. });
  372. } else {
  373. context.prefetchTask.push(task);
  374. context.prefetchStatus = undefined;
  375. context.prefetching = false;
  376. markControl.trigger('task.prefetch.success');
  377. }
  378. }, function(task) {
  379. context.prefetchStatus = task.message;
  380. context.prefetching = false;
  381. markControl.trigger('task.prefetch.none');
  382. }, function() {
  383. context.prefetching = false;
  384. markControl.trigger('task.prefetch.none');
  385. });
  386. }
  387. } else {
  388. markControl.trigger('task.prefetch.finish');
  389. }
  390. }
  391. MarkControl.prototype.getStatus = function() {
  392. if (this.taskControl == undefined) {
  393. return;
  394. }
  395. var self = this;
  396. this.taskControl.status(function(status) {
  397. self.context.status = status;
  398. if (status != undefined) {
  399. self.context.isFinish = status.blockTotalCount > 0 && status.blockTotalCount == (status.blockMarkedCount + status.blockExceptionCount);
  400. }
  401. if (self.context.statusCallback != undefined) {
  402. self.context.statusCallback();
  403. }
  404. self.trigger('mark.status.change', status);
  405. })
  406. }
  407. MarkControl.prototype.getTask = function() {
  408. if (this.taskControl == undefined) {
  409. return;
  410. }
  411. var markControl = this;
  412. var context = this.context;
  413. markControl.trigger('task.get.before');
  414. if (context.isFinish == true) {
  415. markControl.trigger('task.get.finish');
  416. return;
  417. } else if (context.task != undefined) {
  418. markControl.trigger('task.get.success');
  419. return;
  420. } else if (context.waitTask != undefined) {
  421. // 优先选择因回评等操作处于等待状态的任务
  422. context.task = context.waitTask;
  423. context.waitTask = undefined;
  424. markControl.trigger('task.get.success');
  425. } else if (context.prefetchTask.length > 0) {
  426. // 判断是否有任务已预加载完毕
  427. context.task = context.prefetchTask.shift();
  428. markControl.trigger('task.get.success');
  429. } else if (context.prefetchStatus != undefined) {
  430. // 判断是否有在无预加载任务的情况下的消息提示
  431. markControl.trigger('task.get.none', context.prefetchStatus);
  432. } else {
  433. markControl.trigger('task.get.none');
  434. }
  435. }
  436. MarkControl.prototype.getHistory = function(data) {
  437. if (this.taskControl == undefined) {
  438. return;
  439. }
  440. this.taskControl.history(data, function(result) {
  441. data.result = result;
  442. this.option.markControl.trigger('history.get.success', data);
  443. }, function(message) {
  444. data.message = message;
  445. this.option.markControl.trigger('history.get.error', data);
  446. });
  447. }
  448. MarkControl.prototype.setTask = function(task) {
  449. var imageBuilder = this.modules['image-builder'];
  450. var self = this;
  451. if (this.context.task != undefined && !this.context.task.previous && this.context.waitTask == undefined) {
  452. this.context.waitTask = this.context.task;
  453. }
  454. this.trigger('task.get.before');
  455. if (imageBuilder != undefined && task != undefined) {
  456. imageBuilder.build(task, function(error) {
  457. self.context.task = task;
  458. self.trigger('task.get.success');
  459. });
  460. } else {
  461. self.context.task = task;
  462. if (task != undefined) {
  463. this.trigger('task.get.success');
  464. }
  465. }
  466. }
  467. MarkControl.prototype.submitTask = function(submitUrl) {
  468. var task = this.context.task;
  469. var markControl = this;
  470. var submitUrl = submitUrl != undefined && submitUrl.length > 0 ? submitUrl : this.option.submitUrl;
  471. if (task != undefined && this.context.submitting != true) {
  472. //开启强制标记
  473. if(this.option.forceSpecialTag===true){
  474. var isTag = !(task.tagList==undefined ||task.tagList==null ||task.tagList.length <= 0);
  475. var isTrack = false;
  476. for(var i in task.trackList) {
  477. var track = task.trackList[i];
  478. if(track.positionX!=0 || track.positionY!=0 ){
  479. isTrack = true;
  480. }
  481. }
  482. if(!(isTag||isTrack)){
  483. markControl.trigger('task.submit.forceSpecialTag');
  484. return;
  485. }
  486. }
  487. task.markStepList = undefined;
  488. task.pictureUrls = undefined;
  489. task.sheetUrls = undefined;
  490. task.imageData = undefined;
  491. task.markFinish = undefined;
  492. task.markTime = undefined;
  493. task.paperUrl = undefined;
  494. task.answerUrl = undefined;
  495. var timestamp = new Date().getTime();
  496. task.spent = timestamp - task.spent;
  497. this.trigger('task.submit.before');
  498. this.trigger('mark.specialTag.before');
  499. if (this.taskControl != undefined) {
  500. // 已定义任务引擎
  501. this.taskControl.submit(task, function(status) {
  502. if (status != undefined && status.valid == true) {
  503. markControl.context.status = status;
  504. markControl.trigger('mark.status.change', status);
  505. }
  506. // markControl.context.task = undefined;
  507. markControl.trigger('task.submit.success');
  508. markControl.trigger('mark.specialTag.success');
  509. // markControl.getTask();
  510. }, function(message) {
  511. markControl.trigger('task.submit.error', message);
  512. });
  513. } else if (submitUrl != undefined && submitUrl.length > 0) {
  514. // 未定义任务引擎,依赖定义/传入的提交地址
  515. $.ajax({
  516. url: submitUrl,
  517. type: 'POST',
  518. data: task,
  519. success: function(result) {
  520. if (result.success == true) {
  521. // markControl.context.task = undefined;
  522. markControl.trigger('task.submit.success');
  523. markControl.trigger('mark.specialTag.success');
  524. // markControl.getTask();
  525. } else {
  526. markControl.trigger('task.submit.error', result.message);
  527. }
  528. },
  529. error: function(message) {
  530. markControl.trigger('task.submit.error', message);
  531. }
  532. });
  533. } else {
  534. markControl.trigger('task.submit.success');
  535. markControl.trigger('mark.specialTag.success');
  536. // markControl.getTask();
  537. }
  538. }
  539. }
  540. // 默认要初始化的模块名称
  541. MarkControl.prototype.defaultModules = {
  542. 'image-builder': {}
  543. };
  544. MarkControl.prototype.main_row_dom = '<div class="row-fluid"></div>';
  545. MarkControl.prototype.sidebar_dom = '<div class="mark-sidebar span2 hide"></div>';
  546. MarkControl.prototype.center_dom = '<div class="center-content span12"></div>';
  547. MarkControl.prototype.center_header_dom = '<div class="row-fluid"><div class="header"><p class="tips">\
  548. <em><a href="##" class="btn" id="switch-common-button" style="display:none">切换到普通模式</a>\
  549. <a href="javascript:void(0)" id="assistant-button" class="btn"><i class="icon-wrench"></i> 小助手</a></em>\
  550. <a class="useinfo" href="#"><i class="icon-user icon-white"></i><i id="mark-user-name"></i></a>\
  551. <a class="logout" id="logout-link" href="{logoutUrl}"><i class="icon-off icon-white"></i> <i id="logout-title">退出</i></a>\
  552. </p></div></div>';
  553. MarkControl.prototype.center_content_dom = '<div class="row-fluid"><div class="image-content span9"><nav></nav></div></div>';
  554. MarkControl.prototype.assistant_dom = '<div class="popover bottom assistant"><div class="arrow"></div></div>';
  555. MarkControl.prototype.mark_function_dom = '<h3 class="popover-title">评卷功能</h3>\
  556. <div class="popover-content"><p id="function-list" class="popover-list">\
  557. </p></div>';
  558. // 其他通用方法
  559. String.prototype.startWith = function(prefix) {
  560. return this.indexOf(prefix) === 0;
  561. }
  562. String.prototype.endWith = function(suffix) {
  563. return this.match(suffix + "$") == suffix;
  564. };
  565. // 日期格式化
  566. Date.prototype.format = function(fmt) { // author: meizz
  567. var o = {
  568. "M+": this.getMonth() + 1, // 月份
  569. "d+": this.getDate(), // 日
  570. "h+": this.getHours(), // 小时
  571. "m+": this.getMinutes(), // 分
  572. "s+": this.getSeconds(), // 秒
  573. "q+": Math.floor((this.getMonth() + 3) / 3), // 季度
  574. "S": this.getMilliseconds() // 毫秒
  575. };
  576. if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
  577. for (var k in o) {
  578. if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
  579. }
  580. return fmt;
  581. }
  582. function getDom(content, markControl) {
  583. if (markControl != undefined && markControl.option.staticServer != undefined) {
  584. content = content.replace(/{staticServer}/g, markControl.option.staticServer);
  585. }
  586. if (markControl != undefined && markControl.option.logoutUrl != undefined) {
  587. content = content.replace(/{logoutUrl}/g, markControl.option.logoutUrl);
  588. }
  589. return $(content);
  590. }
  591. function isArray(obj) {
  592. return obj != undefined && Object.prototype.toString.call(obj) === '[object Array]';
  593. }