Virtonomica:Notes

Система добавления и показа оповещений

当前为 2019-07-12 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Virtonomica:Notes
  3. // @name:en Virtonomica:Notes
  4. // @namespace Virtonomica
  5. // @description Система добавления и показа оповещений
  6. // @description:en The list of notes
  7. // @version 0.26.4
  8. // @include https://*virtonomic*.*/*/main/unit/view/*
  9. // @include https://*virtonomic*.*/*/main/company/view/*/unit_list
  10. // @include https://*virtonomic*.*/*/main/company/view/*/unit_list?new
  11. // @include https://*irtonomic*.*/*/main/politics/president/*
  12. // @include https://*virtonomic*.*/*/main/politics/governor/*
  13. // @include https://*virtonomic*.*/*/main/politics/mayor/*
  14. // ==/UserScript==
  15. var run = function() {
  16. var win = (typeof(unsafeWindow) != 'undefined' ? unsafeWindow : top.window);
  17. $ = win.$;
  18.  
  19. var loc_storage = function(){
  20. return({
  21. 'save': function (name, val){
  22. try {
  23. window.localStorage.setItem( name, JSON.stringify( val ) );
  24. } catch(e) {
  25. out = "Ошибка добавления в локальное хранилище";
  26. //console.log(out);
  27. }
  28. },
  29. 'load': function(name){
  30. obj = JSON.parse( window.localStorage.getItem(name) );
  31. if ( obj == null ) obj = new Object();
  32. return obj;
  33. }
  34. });
  35. }
  36. var LS = new loc_storage();
  37.  
  38. // определяем интерфейс
  39. // autodefined language interface
  40. var lang = 'undef';
  41. //var bt_logout = $("li[class='icon menulogout']");
  42. //var logout_string = bt_logout.attr('title');
  43. var logout_string = $("a[href*='user/logout']").text();
  44. console.log(logout_string);
  45. // язык по умолчанию
  46. lang = 'En';
  47. if (logout_string == 'Выход') {
  48. lang = 'Ru';
  49. } else if(logout_string == 'Logout') {
  50. lang = 'En';
  51. }
  52. console.log(lang);
  53. if ( lang == 'undef') {
  54. alert('Unsupported language for userscript "Notes"');
  55. return;
  56. }
  57.  
  58. // Строки зависимые от языка
  59. // language definitions
  60. var LangMsg = new Object();
  61. LangMsg['Ru'] = new Object();
  62. LangMsg['En'] = new Object();
  63.  
  64. LangMsg['Ru']['governor'] = "Губернатор";
  65. LangMsg['En']['governor'] = "Governor";
  66. LangMsg['Ru']['president'] = "Президент";
  67. LangMsg['En']['president'] = "President";
  68. LangMsg['Ru']['mayor'] = "Мэр";
  69. LangMsg['En']['mayor'] = "Mayor";
  70.  
  71. LangMsg['Ru']['notes'] = "Напоминание";
  72. LangMsg['En']['notes'] = "Notes";
  73.  
  74. LangMsg['Ru']['list_notes'] = "Список напоминаний";
  75. LangMsg['En']['list_notes'] = "List of Notes";
  76.  
  77. LangMsg['Ru']['save'] = "Сохранить";
  78. LangMsg['En']['save'] = "Save";
  79. LangMsg['Ru']['del'] = "Удалить";
  80. LangMsg['En']['del'] = "Delete";
  81.  
  82. LangMsg['Ru']['add_notes'] = "Добавить напоминание";
  83. LangMsg['En']['add_notes'] = "Add Notes";
  84.  
  85. LangMsg['Ru']['export'] = "Окно экспорта/импорта";
  86. LangMsg['En']['export'] = "Windwow export/import";
  87. LangMsg['Ru']['import'] = "Импортировать данные из окна";
  88. LangMsg['En']['import'] = "Importing data from textarea";
  89. LangMsg['Ru']['data_export'] = "Данные экспорта";
  90. LangMsg['En']['data_export'] = "Data exporting";
  91. // --- virtonomica user interface
  92. LangMsg['Ru']['comp'] = "компании";
  93. LangMsg['En']['comp'] = "of a company";
  94. // Стили
  95. var st = $("style");
  96. if ( $(".my_btn", st).length == 0 ) {
  97. st.append(".my_btn{cursor:pointer;opacity:0.5;float:left;color: white;}");
  98. st.append(".my_btn:hover{opacity:1.0}");
  99. st.append(".my_btn img {width:20px;}");
  100. st.append(".table_row:hover{background-color: lightgray;}");
  101. //css("text-decoration","line-through").css("color","grey");
  102. st.append(".del_line:{text-decoration:line-through;color:grey}");
  103. st.append(".del_line a, .del_line td, .del_line td img, .del_line td font img {text-decoration:line-through;color:grey;opacity:0.5}");
  104. st.append(".unit_name{padding: 4px;}");
  105.  
  106. }
  107.  
  108. //console.log( LangMsg );
  109. /**
  110. * записать данные в локальнео хранилище, с проверкой ошибок
  111. */
  112. function ToStorage(name, val)
  113. {
  114. try {
  115. window.localStorage.setItem( name, JSON.stringify( val ) );
  116. } catch(e) {
  117. out = "Ошибка добавления в локальное хранилище";
  118. //console.log(out);
  119. }
  120. }
  121.  
  122. function getFromStorage(obj, id_shop)
  123. {
  124. if (obj[id_shop] == null) return '';
  125. return JSON.stringify(obj[id_shop]);
  126. }
  127.  
  128. /**
  129. * Добавить заметку к текущему предприятию
  130. * следует вызывать на страницах где одно подраздление, ИД которого виден в url
  131. *
  132. * @param msg текст сообщения, можно использовать html теги
  133. */
  134. function addNotes( msg ){
  135. // объект для хранения сообщений
  136. notes = JSON.parse( window.localStorage.getItem('notes') );
  137. if ( notes == null ) notes = new Object();
  138.  
  139. // Идентификатор подразделения
  140. var id = /(\d+)/.exec(location.href)[0];
  141. // дизайн от 16.10.2017
  142. var title = $("div.title h1").text();
  143. var type = $.trim( $('ul.tabu li').eq(1).text() );
  144. if ( notes[id] == null ) notes[id] = new Object();
  145.  
  146. var d = new Date();
  147.  
  148. if ( notes[id]['text'] != null) {
  149. // сообщение для этого подраздления уже есть
  150. msg = notes[id]['text'] + "<br>" + msg;
  151. }
  152.  
  153. notes[id]['text'] = msg;
  154. // Количество миллисекунд
  155. notes[id]['time'] = d.getTime();
  156. notes[id]['name'] = title;
  157. notes[id]['type'] = type;
  158.  
  159. ToStorage('notes', notes);
  160. }
  161.  
  162. var txt = "<table><tr><td><td><table width=100%><tr><td align=rigth id=notes_title><td align=center><h3>" + LangMsg[ lang ]['notes'] + "</h3><div id=notes_link style='color:grey'></div></table><td>&nbsp;";
  163. txt+= "";
  164. txt+= "<tr><td>&nbsp;<td align=center id=notes_form>&nbsp;<td>&nbsp;" + "<tr><td colspan=3></table>";
  165. var div_form = "<div id=notes style='background: none repeat scroll 0% 0% rgb(223, 223, 223); z-index: 1002; position: absolute; border: 1px solid rgb(0, 0, 0); display: none;'>" + txt + "</div>";
  166.  
  167. var div_export = "<div id=notes_export style='background: none repeat scroll 0% 0% rgb(223, 223, 223); z-index: 1003; position: absolute; border: 1px solid rgb(0, 0, 0); display: none;'>"
  168. + "<h3 style='margin:4px'>" + LangMsg[ lang ]['data_export'] + "</h3>"
  169. + "<table><tr><td>&nbsp;<td>"
  170. + "<textarea name=export_text id=export_text rows=10 cols=64></textarea>"
  171. + "<br><center><span id=export_load></span></center>"
  172. + "</table>";
  173. + "</div>";
  174.  
  175. // старй дизайн списка юниов (2104 года)
  176. var tu = $("table.unit-list-2014");
  177. // если не нашли старй дизайн, то пробуем найти новый
  178. if ( tu.length == 0) {
  179. tu = $("table.unit_list_table");
  180. }
  181. if (tu.length == 1) {
  182. // Это у нас список подразделений - рисуем кнопку отображения отчета со сылками
  183. // Оповещения
  184. notes = JSON.parse( window.localStorage.getItem('notes') );
  185. if ( notes == null ) notes = new Object();
  186. var len = 0;
  187.  
  188. // проверить, какие оповещения отразить как актуальные
  189. for (key in notes){
  190. len++;
  191. }
  192.  
  193. // http://cdn1.iconfinder.com/data/icons/Upojenie_by_SoundForge/Icons/Notes.png
  194. // http://www.iconsearch.ru/uploads/icons/crystalclear/24x24/kedit.png
  195.  
  196. var wc = $("<li><div id=main_notes class=my_btn> <img alt='" + LangMsg[ lang ]['list_notes'] +"' src=http://cdn1.iconfinder.com/data/icons/humano2/32x32/apps/gnome-sticky-notes-applet.png> <span id=all_notes> ("+ len+")</span></div>").click( function() {
  197. $("#notes").toggle();
  198. if( $('#notes').is(':visible') ) {
  199. // код для visible
  200. // Оповещения
  201. notes = JSON.parse( window.localStorage.getItem('notes') );
  202. if ( notes == null ) notes = new Object();
  203.  
  204. // Формируем ссылку на торговый зал
  205. var url = /^https:\/\/virtonomic[as]\.(\w+)\/\w+\//.exec(location.href)[0];
  206. console.log(url);
  207.  
  208. var all_count = 0;
  209. $("#notes_form").html('');
  210. var out = $("<table>");
  211. for (key in notes){
  212. if (notes[key] == null) continue;
  213. if (notes[key]['time'] == null) continue;
  214.  
  215. // подсчитываем сколько у нас оповещениий
  216. // TODO - учитывать только акутальные
  217. all_count++;
  218.  
  219. var d = new Date();
  220. d.setTime(notes[key]['time']);
  221.  
  222. var link_text = notes[key]['name'];
  223. if ( link_text == '' ) {
  224. link_text = key;
  225. }
  226. link = "<a href=" + url + "main/unit/view/" + key + ">" + link_text + "</a>";
  227. if ( notes[key]['link'] != null ) {
  228. link = "<a href=" + notes[key]['link'] + ">" + link_text + "</a>";
  229. }
  230. span = $("<span name=" + key + " style='cursor:pointer;' title='del'><font color=red><b>Х</b></font></span>").click(
  231. function(){
  232. idp = $(this).attr('name');
  233. //alert('del = ' + idp);
  234. delete notes[idp];
  235. ToStorage('notes', notes);
  236. $(this).parent().addClass("del_line");
  237.  
  238. //$("#main_notes").click().click();
  239. });
  240.  
  241. out_tr = $("<tr class='table_row'>");
  242. out_tr.append("<td>" + d.toLocaleDateString())
  243. .append("<td class=unit_name>" + link)
  244. .append("<td>(" + notes[key]['type'] + ")")
  245. .append("<td style='border: 1px solid gray; border-radius: 4px 4px 4px 4px; box-shadow: 0 1px 3px 0 #999999; display: block; float: left; margin-top: 4px; overflow: hidden; padding: 2px 4px; text-align:left'>" + notes[key]['text'])
  246. .append("<td>").append(span);
  247. out.append(out_tr);
  248. str = "(" + all_count +")";
  249. if (all_count == 0) str = '';
  250. $("#all_notes").html("(" + all_count +")");
  251. }
  252. $("#notes_form").html( out );
  253.  
  254. }
  255. });
  256.  
  257. // http://cdn1.iconfinder.com/data/icons/basicset/save_32.png
  258. // http://www.iconsearch.ru/uploads/icons/ultimategnome/48x48/stock_export.png
  259. var wc_export = $("<span id=main_notes_export style='cursor:pointer; color: white;'><img src=http://cdn1.iconfinder.com/data/icons/basicset/save_32.png title='" + LangMsg[ lang]['export']+ "' alt='О" + LangMsg[ lang]['export']+ "'></span>").click( function() {
  260. $("#export_text").val( JSON.stringify( notes ) );
  261. $("#notes_export").toggle();
  262. });
  263.  
  264. // http://cdn1.iconfinder.com/data/icons/freeapplication/png/24x24/Load.png
  265. // http://www.iconsearch.ru/uploads/icons/freeapplication/24x24/load.png
  266. var wc_load = $("<img src=http://cdn1.iconfinder.com/data/icons/freeapplication/png/24x24/Load.png title='" + LangMsg[ lang ]['import'] + "' alt='" + LangMsg[ lang ]['import'] + "'>").click( function() {
  267. //alert("Load");
  268. var text = $("#export_text").val() ;
  269. try {
  270. notes = JSON.parse( text );
  271. ToStorage('notes', notes);
  272. $("#notes_export").hide();
  273. $("#main_notes").click().click();
  274. } catch(e) {
  275. alert("Неверные данным для импорта");
  276. }
  277. });
  278.  
  279. var container = $('ul.tabu');
  280. container.append( wc );
  281.  
  282. // для старого дизайна
  283. var list_type = $("table.unit-top");
  284. if ( list_type.length == 0 ){
  285. // если не нашли пробуем искать в новом дизайне
  286. list_type = $("div.row");
  287. }
  288. list_type.before ( div_form);
  289. //container.append( div_form );
  290. //var container = $('#topblock');
  291. //container.append( $('<table><tr><td>').append(wc) );
  292. //container.append( div_form );
  293. $("#notes_title").append(wc_export).append( div_export );
  294. $("#export_load").append(wc_load);
  295.  
  296.  
  297. return;
  298. }
  299.  
  300. // Идентификатор подразделения
  301. var id = /(\d+)/.exec(location.href)[0];
  302. console.log("id=" + id);
  303. // тип подразделения
  304. var type = '';
  305. // название подразделения
  306. var title = '';
  307. var pos = location.href.indexOf("politics");
  308. // проверяем на объект политики
  309. if (pos > 0) {
  310. console.log("politics");
  311. // вычитываем название объекта политики
  312. var polit_name = "";
  313. var el = $("#headerInfoCenter h1");
  314. var el2 = $("a", el);
  315. if (el2.length > 0 ) {
  316. polit_name = el2.text();
  317. } else {
  318. polit_name = el.text();
  319. }
  320. if ( location.href.indexOf("president") > 0 ) {
  321. type = LangMsg[ lang ]['president'];
  322. }
  323. if ( location.href.indexOf("governor") > 0 ) {
  324. type = LangMsg[ lang ]['governor'] ;
  325. }
  326. if ( location.href.indexOf("mayor") > 0 ) {
  327. type = LangMsg[ lang ]['mayor'] ;
  328. polit_name = el.html();
  329. pos = polit_name.indexOf("<img");
  330. polit_name = $.trim( polit_name.substr(0, pos) );
  331. }
  332. console.log( polit_name );
  333. title = polit_name;
  334. console.log( type );
  335. } else {
  336. // обработка обыных юнитов (units)
  337. // дизайн от 16.10.2017
  338. var title = $("div.title h1").text();
  339. var type = $.trim( $('ul.tabu li').eq(1).text() );
  340. }
  341. // Оповещения
  342. notes = JSON.parse( window.localStorage.getItem('notes') );
  343. if ( notes == null ) notes = new Object();
  344. if ( notes[id] == null) notes[id] = new Object();
  345.  
  346. notes_html = "";
  347. if ( notes[id]['text'] != null) notes_html = notes[id]['text'];
  348.  
  349. var form = "";
  350. form += "<span id=notes_error style='color:red;'></span><br>";
  351. form += "<div id=notes_preview style='border: 1px solid gray; border-radius: 4px 4px 4px 4px; box-shadow: 0 1px 3px 0 #999999; display: block; float: left; margin-top: 4px; margin-right: 4px; overflow: hidden; padding: 2px 4px; text-align:left'>" + notes_html +"</div>";
  352. form += " <textarea name=notes_txt id=notes_txt rows=5 cols=48>";
  353. form += notes_html;
  354. form+= "</textarea><br>";
  355.  
  356. var form_button = $("<button id=notes_btn style='cursor:pointer'>" +LangMsg[ lang ]['save'] + "</button>").click( function() {
  357. $("#notes_error").text('');
  358. var text = $("#notes_txt").val() ;
  359. $("#notes_preview").html( text );
  360. if (text == '') {
  361. $("#notes_error").text('Ошибка - нет описания');
  362. return;
  363. }
  364.  
  365. var d = new Date();
  366. // Оповещения
  367. notes = JSON.parse( window.localStorage.getItem('notes') );
  368. if ( notes == null ) notes = new Object();
  369.  
  370. if ( notes[id] == null) notes[id] = new Object();
  371.  
  372. notes[id]['text'] = text;
  373. notes[id]['time'] = d.getTime();
  374. notes[id]['name'] = title;
  375. notes[id]['type'] = type;
  376. notes[id]['link'] = location.href;
  377.  
  378. ToStorage('notes', notes);
  379. $("#notes").toggle();
  380. });
  381.  
  382. var form_button_del = $(" <button style='cursor:pointer'>" +LangMsg[ lang ]['del'] + "</button>").click( function() {
  383. // Оповещения
  384. notes = JSON.parse( window.localStorage.getItem('notes') );
  385. if ( notes == null ) notes = new Object();
  386.  
  387. if ( notes[id] == null) notes[id] = new Object();
  388.  
  389. $("#notes_txt").val("");
  390. $("#notes_preview").html( "" );
  391. delete notes[id];
  392. ToStorage('notes', notes);
  393. });
  394.  
  395. // http://cdn1.iconfinder.com/data/icons/oxygen/32x32/actions/document-new.png
  396. // http://www.iconsearch.ru/uploads/icons/ull_icons/24x24/message_add.png
  397. var wc = $("<li class=my_btn><img alt='"+ LangMsg[ lang ]['add_notes'] + "' src=http://cdn1.iconfinder.com/data/icons/oxygen/32x32/actions/document-new.png title='"+ LangMsg[ lang ]['add_notes'] + "'> </li>").click( function() {
  398. $("#notes").toggle();
  399. // Обновить зампетку
  400. notes = JSON.parse( window.localStorage.getItem('notes') );
  401. if ( notes == null ) notes = new Object();
  402. if ( notes[id] == null) notes[id] = new Object();
  403.  
  404. $("#notes_txt").change(function() {
  405. console.log('change ' + $("#notes_txt").val() );
  406. $("#notes_preview").html( $("#notes_txt").val() );
  407. });
  408. if ( notes[id]['text'] == null ) return;
  409. $("#notes_txt").val( notes[id]['text'] );
  410. $("#notes_preview").html( notes[id]['text'] );
  411. if (notes[id]['link'] != null) {
  412. $("#notes_link").html( notes[id]['link'] );
  413. }
  414. });
  415. //var container = $('#topblock');
  416. //var container = $('#topblock').next();
  417. var container = $('ul.tabu');
  418.  
  419. if (tu.length == 0) {
  420. container = $("li:last", container).prev().parent();
  421. container.append(wc) ;
  422. //container.append( $('<table><tr><td>').append(wc) );
  423. $("#childMenu").before ( div_form);
  424.  
  425. $("#notes_form").append(form).append(form_button).append(form_button_del);
  426. }
  427. }
  428.  
  429. if(window.top == window) {
  430. var script = document.createElement("script");
  431. script.textContent = '(' + run.toString() + ')();';
  432. document.documentElement.appendChild(script);
  433. }