Documenteditor.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. MWF.xDesktop.requireApp("process.Xform", "$Module", null, false);
  2. MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor = new Class({
  3. Extends: MWF.APP$Module,
  4. options: {
  5. "moduleEvents": ["load", "postLoad", "afterLoad"]
  6. },
  7. initialize: function(node, json, form, options){
  8. this.node = $(node);
  9. this.node.store("module", this);
  10. this.json = json;
  11. this.form = form;
  12. this.field = true;
  13. },
  14. load: function(){
  15. if (this.fireEvent("queryLoad")){
  16. this._queryLoaded();
  17. this._loadUserInterface();
  18. this._loadStyles();
  19. this._afterLoaded();
  20. this.fireEvent("postLoad");
  21. this.fireEvent("load");
  22. }
  23. },
  24. _loadUserInterface: function(){
  25. this.node.empty();
  26. this.node.setStyles(this.form.css.documentEditorNode);
  27. this.pages = [];
  28. var pageNode = new Element("div.pageNode", {
  29. "styles": this.form.css.documentEditorNode_page
  30. }).inject(this.node);
  31. var config = Object.clone(this.json.editorProperties);
  32. if (this.json.config){
  33. if (this.json.config.code){
  34. var obj = MWF.Macro.exec(this.json.config.code, this);
  35. Object.each(obj, function(v, k){
  36. config[k] = v;
  37. });
  38. }
  39. }
  40. pageNode.setAttribute('contenteditable', true);
  41. this.loadCkeditor(config, pageNode);
  42. // if (this.readonly){
  43. // this.node.set("html", this._getBusinessData());
  44. // this.node.setStyles({
  45. // "-webkit-user-select": "text",
  46. // "-moz-user-select": "text"
  47. // });
  48. // }else{
  49. // var config = Object.clone(this.json.editorProperties);
  50. // if (this.json.config){
  51. // if (this.json.config.code){
  52. // var obj = MWF.Macro.exec(this.json.config.code, this);
  53. // Object.each(obj, function(v, k){
  54. // config[k] = v;
  55. // });
  56. // }
  57. // }
  58. // this.loadCkeditor(config);
  59. // }
  60. },
  61. loadCkeditor: function(config, pageNode){
  62. COMMON.AjaxModule.loadDom("ckeditor", function(){
  63. CKEDITOR.disableAutoInline = true;
  64. //var editorDiv = new Element("div").inject(this.node);
  65. var editorDiv = pageNode;
  66. var htmlData = this._getBusinessData();
  67. if (htmlData){
  68. editorDiv.set("html", htmlData);
  69. }else if (this.json.templateCode){
  70. editorDiv.set("html", this.json.templateCode);
  71. }
  72. var height = this.node.getSize().y;
  73. var editorConfig = config || {};
  74. if (this.form.json.mode==="Mobile"){
  75. if (!editorConfig.toolbar && !editorConfig.toolbarGroups){
  76. editorConfig.toolbar = [
  77. { name: 'paragraph', items: [ 'Bold', 'Italic', "-" , 'TextColor', "BGColor", 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', "-", 'Undo', 'Redo' ] },
  78. { name: 'basicstyles', items: [ 'Styles', 'FontSize']}
  79. ];
  80. }
  81. }
  82. var editorConfig = {};
  83. editorConfig.localImageMaxWidth = 800;
  84. editorConfig.reference = this.form.businessData.work.job;
  85. editorConfig.referenceType = "processPlatformJob";
  86. editorConfig.toolbarGroups = [
  87. { name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
  88. { name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
  89. { name: 'editing', groups: [ 'find', 'selection', 'spellchecker', 'editing' ] },
  90. { name: 'forms', groups: [ 'forms' ] },
  91. { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi', 'paragraph' ] },
  92. { name: 'insert', groups: [ 'insert' ] },
  93. { name: 'tools', groups: [ 'tools' ] },
  94. '/',
  95. { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
  96. { name: 'links', groups: [ 'links' ] },
  97. '/',
  98. { name: 'styles', groups: [ 'styles' ] },
  99. { name: 'colors', groups: [ 'colors' ] },
  100. { name: 'others', groups: [ 'others' ] },
  101. { name: 'about', groups: [ 'about' ] }
  102. ];
  103. editorConfig.removeButtons = 'Templates,Scayt,Form,Bold,Italic,Underline,Strike,Subscript,Superscript,CopyFormatting,RemoveFormat,Indent,Outdent,Blockquote,CreateDiv,BidiLtr,BidiRtl,Language,Link,Unlink,Anchor,Flash,HorizontalRule,Smiley,SpecialChar,Iframe,PageBreak,Styles,Format,Font,FontSize,TextColor,BGColor,About,Checkbox,Radio,TextField,Textarea,Select,Button,ImageButton,HiddenField';
  104. // editorConfig.bodyClass = "document-editor";
  105. editorConfig.contentsCss = [ '/x_component_process_Xform/$Form/doc.css' ];
  106. editorConfig.extraPlugins = ['ecnet','doc_redHeader'];
  107. editorConfig.allowedContent = "div(o2_editorPlugin_redHeader)";
  108. editorConfig.disableAutoInline = false;
  109. this.editor = CKEDITOR.inline(editorDiv, editorConfig);
  110. //this.editor = CKEDITOR.inline(editorDiv);
  111. debugger;
  112. this.editor.on("key",function(e){
  113. var sel = e.editor.getSelection();
  114. var h = e.editor.getSelectedHtml().getHtml();
  115. if (h.indexOf("o2_editorPlugin_redHeader")!=-1 ||
  116. h.indexOf("o2_editorPlugin_doc_Page")!=-1){
  117. e.cancel();
  118. }
  119. debugger;
  120. var el = sel.getSelectedElement();
  121. })
  122. //
  123. //
  124. // this._loadEvents();
  125. // this.editor.on("change", function(){
  126. // //this._setBusinessData(this.getData());
  127. // }.bind(this));
  128. }.bind(this));
  129. },
  130. getEcnetString: function(node, nodes){
  131. for (var i=0; i<node.childNodes.length; i++){
  132. if (node.childNodes[i].nodeType===Node.TEXT_NODE){
  133. var s = this.ecnetString.length;
  134. this.ecnetString += node.childNodes[i].nodeValue;
  135. var e = this.ecnetString.length;
  136. nodes.push({
  137. "pnode": node,
  138. "node": node.childNodes[i],
  139. "start": s, "end": e
  140. });
  141. }else{
  142. this.getEcnetString(node.childNodes[i], nodes);
  143. }
  144. }
  145. },
  146. createEcnetNode: function(node){
  147. var newNode = node.node.ownerDocument.createElement("span");
  148. var increment = 0;
  149. var html = node.node.nodeValue;;
  150. node.ecnets.each(function(ecnet){
  151. var s = ecnet.begin+increment-node.start;
  152. var e = ecnet.end+increment-node.start;
  153. if (s<0) s=0;
  154. if (e>node.end+increment) e = node.end+increment;
  155. var length = html.length;
  156. var left = html.substring(0, s);
  157. var ecnetStr = html.substring(s, e);
  158. var right = html.substring(e, html.length);
  159. html = left+"<span class='o2_ecnet_item' style='color: red'><u>"+ecnetStr+"</u></span>"+right;
  160. increment += (html.length-length);
  161. }.bind(this));
  162. newNode.innerHTML = html;
  163. node.pnode.replaceChild(newNode, node.node);
  164. node.pnode.textNode = node.node;
  165. node.pnode.ecnetNode = newNode;
  166. var _self = this;
  167. var editorFrame = this.editor.document.$.defaultView.frameElement;
  168. var spans = newNode.getElementsByTagName("span");
  169. if (spans.length){
  170. for (var i = 0; i<spans.length; i++){
  171. var span = spans[i];
  172. if (span.className==="o2_ecnet_item"){
  173. var ecnetNode = new Element("div", {"styles": {
  174. "border": "1px solid #999999",
  175. "box-shadow": "0px 0px 5px #999999",
  176. "background-color": "#ffffff",
  177. "position": "fixed",
  178. "display": "none"
  179. }}).inject(editorFrame, "after");
  180. var correctNode = new Element("div", {
  181. "styles": {
  182. "padding": "3px 10px",
  183. "font-weight": "bold",
  184. "font-size": "12px",
  185. "cursor": "pointer"
  186. },
  187. "text": node.ecnets[i].origin+"->"+node.ecnets[i].correct,
  188. "events": {
  189. "mouseover": function(){this.setStyle("background-color", "#dddddd")},
  190. "mouseout": function(){this.setStyle("background-color", "#ffffff")},
  191. "mousedown": function(){
  192. var ecnetNode = this.getParent();
  193. var node = ecnetNode.node;
  194. var item = ecnetNode.node.ecnets[ecnetNode.idx];
  195. var textNode = node.node.ownerDocument.createTextNode(item.correct);
  196. ecnetNode.span.parentNode.replaceChild(textNode, ecnetNode.span);
  197. ecnetNode.destroy();
  198. node.node.nodeValue = node.pnode.ecnetNode.innerText;
  199. node.ecnets.erase(item);
  200. if (!node.ecnets.length){
  201. _self.ecnetNodes.erase(node);
  202. }
  203. }
  204. }
  205. }).inject(ecnetNode);
  206. var ignoreNode = new Element("div", {
  207. "styles": {
  208. "padding": "3px 10px",
  209. "font-size": "12px",
  210. "cursor": "pointer"
  211. },
  212. "text": MWF.xApplication.process.Xform.LP.ignore,
  213. "events": {
  214. "mouseover": function(){this.setStyle("background-color", "#dddddd")},
  215. "mouseout": function(){this.setStyle("background-color", "#ffffff")},
  216. "mousedown": function(){
  217. var ecnetNode = this.getParent();
  218. var node = ecnetNode.node;
  219. var item = ecnetNode.node.ecnets[ecnetNode.idx];
  220. var textNode = node.node.ownerDocument.createTextNode(ecnetNode.span.innerText);
  221. ecnetNode.span.parentNode.replaceChild(textNode, ecnetNode.span);
  222. ecnetNode.destroy();
  223. node.node.nodeValue = node.pnode.ecnetNode.innerText;
  224. node.ecnets.erase(item);
  225. if (!node.ecnets.length){
  226. _self.ecnetNodes.erase(node);
  227. }
  228. }
  229. }
  230. }).inject(ecnetNode);
  231. ecnetNode.node = node;
  232. ecnetNode.idx = i;
  233. span.ecnetNode = ecnetNode;
  234. ecnetNode.span = span;
  235. span.addEventListener("click", function(){
  236. var ecnetNode = this.ecnetNode;
  237. ecnetNode.show();
  238. var y = this.offsetTop;
  239. var x = this.offsetLeft;
  240. var w = this.offsetWidth;
  241. var h = this.offsetHeight;
  242. var p = editorFrame.getPosition();
  243. var s = ecnetNode.getSize();
  244. var top = y+p.y+h+5;
  245. var left = x+p.x-((s.x-w)/2);
  246. ecnetNode.style.left = ""+left+"px";
  247. ecnetNode.style.top = ""+top+"px";
  248. var _span = this;
  249. var hideEcnetNode = function(){
  250. ecnetNode.hide();
  251. _span.ownerDocument.removeEventListener("mousedown", hideEcnetNode);
  252. };
  253. this.ownerDocument.addEventListener("mousedown", hideEcnetNode);
  254. });
  255. }
  256. }
  257. }
  258. },
  259. clearEcnetNodes: function(){
  260. if (this.ecnetNodes && this.ecnetNodes.length){
  261. this.ecnetNodes.each(function(node){
  262. if (node.pnode.ecnetNode){
  263. if (node.pnode.ecnetInforNode) node.pnode.ecnetInforNode.destroy();
  264. node.pnode.ecnetInforNode = null;
  265. node.pnode.replaceChild(node.pnode.textNode, node.pnode.ecnetNode);
  266. }
  267. }.bind(this));
  268. this.ecnetNodes = [];
  269. }
  270. },
  271. ecnet: function(data){
  272. //this.editor.document.$.body.innerText
  273. var editorFrame = this.editor.document.$.defaultView.frameElement;
  274. //var data = this.editor.getData();
  275. var body = this.editor.document.$.body;
  276. if (!this.ecnetNodes) this.ecnetNodes = [];
  277. if (this.ecnetNodes.length) this.clearEcnetNodes();
  278. var nodes = [];
  279. this.ecnetString = "";
  280. this.getEcnetString(body, nodes);
  281. MWF.Actions.get("x_general_assemble_control").ecnetCheck({"value": this.ecnetString}, function(json){
  282. if (json.data.itemList && json.data.itemList.length){
  283. nodes.each(function(node){
  284. var items = [];
  285. json.data.itemList.each(function(item){
  286. if ((node.end<=item.end && node.end>item.begin) || (node.start>=item.begin && node.start<item.end) || (node.start<=item.begin && node.end>item.end)){
  287. items.push(item);
  288. }
  289. }.bind(this));
  290. if (items.length){
  291. node.ecnets = items;
  292. this.ecnetNodes.push(node);
  293. }
  294. }.bind(this));
  295. this.ecnetNodes.each(function(node){
  296. this.createEcnetNode(node);
  297. }.bind(this));
  298. }else{
  299. body = null;
  300. nodes = null;
  301. }
  302. }.bind(this));
  303. },
  304. _loadEvents: function(editorConfig){
  305. Object.each(this.json.events, function(e, key){
  306. if (e.code){
  307. this.editor.on(key, function(event){
  308. return this.form.Macro.fire(e.code, this, event);
  309. }.bind(this), this);
  310. }
  311. }.bind(this));
  312. },
  313. _loadValue: function(){
  314. var data = this._getBusinessData();
  315. },
  316. resetData: function(){
  317. this.setData(this._getBusinessData());
  318. },
  319. getData: function(){
  320. this.clearEcnetNodes();
  321. return this.editor.getData();
  322. },
  323. setData: function(data){
  324. this._setBusinessData(data);
  325. if (this.editor) this.editor.setData(data);
  326. },
  327. createErrorNode: function(text){
  328. var node = new Element("div");
  329. var iconNode = new Element("div", {
  330. "styles": {
  331. "width": "20px",
  332. "height": "20px",
  333. "float": "left",
  334. "background": "url("+"/x_component_process_Xform/$Form/default/icon/error.png) center center no-repeat"
  335. }
  336. }).inject(node);
  337. var textNode = new Element("div", {
  338. "styles": {
  339. "line-height": "20px",
  340. "margin-left": "20px",
  341. "color": "red",
  342. "word-break": "keep-all"
  343. },
  344. "text": text
  345. }).inject(node);
  346. return node;
  347. },
  348. notValidationMode: function(text){
  349. if (!this.isNotValidationMode){
  350. this.isNotValidationMode = true;
  351. this.node.store("borderStyle", this.node.getStyles("border-left", "border-right", "border-top", "border-bottom"));
  352. this.node.setStyle("border", "1px solid red");
  353. this.errNode = this.createErrorNode(text).inject(this.node, "after");
  354. this.showNotValidationMode(this.node);
  355. }
  356. },
  357. showNotValidationMode: function(node){
  358. var p = node.getParent("div");
  359. if (p){
  360. if (p.get("MWFtype") == "tab$Content"){
  361. if (p.getParent("div").getStyle("display")=="none"){
  362. var contentAreaNode = p.getParent("div").getParent("div");
  363. var tabAreaNode = contentAreaNode.getPrevious("div");
  364. var idx = contentAreaNode.getChildren().indexOf(p.getParent("div"));
  365. var tabNode = tabAreaNode.getLast().getFirst().getChildren()[idx];
  366. tabNode.click();
  367. p = tabAreaNode.getParent("div");
  368. }
  369. }
  370. this.showNotValidationMode(p);
  371. }
  372. },
  373. validationMode: function(){
  374. if (this.isNotValidationMode){
  375. this.isNotValidationMode = false;
  376. this.node.setStyles(this.node.retrieve("borderStyle"));
  377. if (this.errNode){
  378. this.errNode.destroy();
  379. this.errNode = null;
  380. }
  381. }
  382. },
  383. validationConfigItem: function(routeName, data){
  384. var flag = (data.status=="all") ? true: (routeName == data.decision);
  385. if (flag){
  386. var n = this.getData();
  387. var v = (data.valueType=="value") ? n : n.length;
  388. switch (data.operateor){
  389. case "isnull":
  390. if (!v){
  391. this.notValidationMode(data.prompt);
  392. return false;
  393. }
  394. break;
  395. case "notnull":
  396. if (v){
  397. this.notValidationMode(data.prompt);
  398. return false;
  399. }
  400. break;
  401. case "gt":
  402. if (v>data.value){
  403. this.notValidationMode(data.prompt);
  404. return false;
  405. }
  406. break;
  407. case "lt":
  408. if (v<data.value){
  409. this.notValidationMode(data.prompt);
  410. return false;
  411. }
  412. break;
  413. case "equal":
  414. if (v==data.value){
  415. this.notValidationMode(data.prompt);
  416. return false;
  417. }
  418. break;
  419. case "neq":
  420. if (v!=data.value){
  421. this.notValidationMode(data.prompt);
  422. return false;
  423. }
  424. break;
  425. case "contain":
  426. if (v.indexOf(data.value)!=-1){
  427. this.notValidationMode(data.prompt);
  428. return false;
  429. }
  430. break;
  431. case "notcontain":
  432. if (v.indexOf(data.value)==-1){
  433. this.notValidationMode(data.prompt);
  434. return false;
  435. }
  436. break;
  437. }
  438. }
  439. return true;
  440. },
  441. validationConfig: function(routeName, opinion){
  442. if (this.json.validationConfig){
  443. if (this.json.validationConfig.length){
  444. for (var i=0; i<this.json.validationConfig.length; i++) {
  445. var data = this.json.validationConfig[i];
  446. if (!this.validationConfigItem(routeName, data)) return false;
  447. }
  448. }
  449. return true;
  450. }
  451. return true;
  452. },
  453. validation: function(routeName, opinion){
  454. if (!this.validationConfig(routeName, opinion)) return false;
  455. if (!this.json.validation) return true;
  456. if (!this.json.validation.code) return true;
  457. var flag = this.form.Macro.exec(this.json.validation.code, this);
  458. if (!flag) flag = MWF.xApplication.process.Xform.LP.notValidation;
  459. if (flag.toString()!="true"){
  460. this.notValidationMode(flag);
  461. return false;
  462. }
  463. return true;
  464. }
  465. });