");
549 | $("tr:first td", table.tBodies[0]).each(function () {
550 | colgroup.append($("").css("width", $(this).width()));
551 | });
552 | $(table).prepend(colgroup);
553 | }
554 | }
555 |
556 | function updateHeaderSortCount(table, sortList) {
557 | var c = table.config,
558 | l = sortList.length;
559 | for (var i = 0; i < l; i++) {
560 | var s = sortList[i],
561 | o = c.headerList[s[0]];
562 | o.count = s[1];
563 | o.count++;
564 | }
565 | }
566 |
567 | /* sorting methods */
568 |
569 | var sortWrapper;
570 |
571 | function multisort(table, sortList, cache) {
572 | if (table.config.debug) {
573 | var sortTime = new Date();
574 | }
575 |
576 | var dynamicExp = "sortWrapper = function(a,b) {",
577 | l = sortList.length;
578 |
579 | // TODO: inline functions.
580 | for (var i = 0; i < l; i++) {
581 | var c = sortList[i][0];
582 | var order = sortList[i][1];
583 | // var s = (getCachedSortType(table.config.parsers,c) == "text") ?
584 | // ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ?
585 | // "sortNumeric" : "sortNumericDesc");
586 | // var s = (table.config.parsers[c].type == "text") ? ((order == 0)
587 | // ? makeSortText(c) : makeSortTextDesc(c)) : ((order == 0) ?
588 | // makeSortNumeric(c) : makeSortNumericDesc(c));
589 | var s =
590 | table.config.parsers[c].type == "text"
591 | ? order == 0
592 | ? makeSortFunction("text", "asc", c)
593 | : makeSortFunction("text", "desc", c)
594 | : order == 0
595 | ? makeSortFunction("numeric", "asc", c)
596 | : makeSortFunction("numeric", "desc", c);
597 | var e = "e" + i;
598 |
599 | dynamicExp += "var " + e + " = " + s; // + "(a[" + c + "],b[" + c
600 | // + "]); ";
601 | dynamicExp += "if(" + e + ") { return " + e + "; } ";
602 | dynamicExp += "else { ";
603 | }
604 |
605 | // if value is the same keep orignal order
606 | var orgOrderCol = cache.normalized[0].length - 1;
607 | dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];";
608 |
609 | for (var i = 0; i < l; i++) {
610 | dynamicExp += "}; ";
611 | }
612 |
613 | dynamicExp += "return 0; ";
614 | dynamicExp += "}; ";
615 |
616 | if (table.config.debug) {
617 | benchmark("Evaling expression:" + dynamicExp, new Date());
618 | }
619 |
620 | eval(dynamicExp);
621 |
622 | cache.normalized.sort(sortWrapper);
623 |
624 | if (table.config.debug) {
625 | benchmark("Sorting on " + sortList.toString() + " and dir " + order + " time:", sortTime);
626 | }
627 |
628 | return cache;
629 | }
630 |
631 | function makeSortFunction(type, direction, index) {
632 | var a = "a[" + index + "]",
633 | b = "b[" + index + "]";
634 | if (type == "text" && direction == "asc") {
635 | return (
636 | "(" +
637 | a +
638 | " == " +
639 | b +
640 | " ? 0 : (" +
641 | a +
642 | " === null ? Number.POSITIVE_INFINITY : (" +
643 | b +
644 | " === null ? Number.NEGATIVE_INFINITY : (" +
645 | a +
646 | " < " +
647 | b +
648 | ") ? -1 : 1 )));"
649 | );
650 | } else if (type == "text" && direction == "desc") {
651 | return (
652 | "(" +
653 | a +
654 | " == " +
655 | b +
656 | " ? 0 : (" +
657 | a +
658 | " === null ? Number.POSITIVE_INFINITY : (" +
659 | b +
660 | " === null ? Number.NEGATIVE_INFINITY : (" +
661 | b +
662 | " < " +
663 | a +
664 | ") ? -1 : 1 )));"
665 | );
666 | } else if (type == "numeric" && direction == "asc") {
667 | return (
668 | "(" +
669 | a +
670 | " === null && " +
671 | b +
672 | " === null) ? 0 :(" +
673 | a +
674 | " === null ? Number.POSITIVE_INFINITY : (" +
675 | b +
676 | " === null ? Number.NEGATIVE_INFINITY : " +
677 | a +
678 | " - " +
679 | b +
680 | "));"
681 | );
682 | } else if (type == "numeric" && direction == "desc") {
683 | return (
684 | "(" +
685 | a +
686 | " === null && " +
687 | b +
688 | " === null) ? 0 :(" +
689 | a +
690 | " === null ? Number.POSITIVE_INFINITY : (" +
691 | b +
692 | " === null ? Number.NEGATIVE_INFINITY : " +
693 | b +
694 | " - " +
695 | a +
696 | "));"
697 | );
698 | }
699 | }
700 |
701 | function makeSortText(i) {
702 | return "((a[" + i + "] < b[" + i + "]) ? -1 : ((a[" + i + "] > b[" + i + "]) ? 1 : 0));";
703 | }
704 |
705 | function makeSortTextDesc(i) {
706 | return "((b[" + i + "] < a[" + i + "]) ? -1 : ((b[" + i + "] > a[" + i + "]) ? 1 : 0));";
707 | }
708 |
709 | function makeSortNumeric(i) {
710 | return "a[" + i + "]-b[" + i + "];";
711 | }
712 |
713 | function makeSortNumericDesc(i) {
714 | return "b[" + i + "]-a[" + i + "];";
715 | }
716 |
717 | function sortText(a, b) {
718 | if (table.config.sortLocaleCompare) return a.localeCompare(b);
719 | return a < b ? -1 : a > b ? 1 : 0;
720 | }
721 |
722 | function sortTextDesc(a, b) {
723 | if (table.config.sortLocaleCompare) return b.localeCompare(a);
724 | return b < a ? -1 : b > a ? 1 : 0;
725 | }
726 |
727 | function sortNumeric(a, b) {
728 | return a - b;
729 | }
730 |
731 | function sortNumericDesc(a, b) {
732 | return b - a;
733 | }
734 |
735 | function getCachedSortType(parsers, i) {
736 | return parsers[i].type;
737 | } /* public methods */
738 | this.construct = function (settings) {
739 | return this.each(function () {
740 | // if no thead or tbody quit.
741 | if (!this.tHead || !this.tBodies) return;
742 | // declare
743 | var $this,
744 | $document,
745 | $headers,
746 | cache,
747 | config,
748 | shiftDown = 0,
749 | sortOrder;
750 | // new blank config object
751 | this.config = {};
752 | // merge and extend.
753 | config = $.extend(this.config, $.tablesorter.defaults, settings);
754 | // store common expression for speed
755 | $this = $(this);
756 | // save the settings where they read
757 | $.data(this, "tablesorter", config);
758 | // build headers
759 | $headers = buildHeaders(this);
760 | // try to auto detect column type, and store in tables config
761 | this.config.parsers = buildParserCache(this, $headers);
762 | // build the cache for the tbody cells
763 | cache = buildCache(this);
764 | // get the css class names, could be done else where.
765 | var sortCSS = [config.cssDesc, config.cssAsc];
766 | // fixate columns if the users supplies the fixedWidth option
767 | fixColumnWidth(this);
768 | // apply event handling to headers
769 | // this is to big, perhaps break it out?
770 | $headers
771 | .click(function (e) {
772 | var totalRows = ($this[0].tBodies[0] && $this[0].tBodies[0].rows.length) || 0;
773 | if (!this.sortDisabled && totalRows > 0) {
774 | // Only call sortStart if sorting is
775 | // enabled.
776 | $this.trigger("sortStart");
777 | // store exp, for speed
778 | var $cell = $(this);
779 | // get current column index
780 | var i = this.column;
781 | // get current column sort order
782 | this.order = this.count++ % 2;
783 | // always sort on the locked order.
784 | if (this.lockedOrder) this.order = this.lockedOrder;
785 |
786 | // user only whants to sort on one
787 | // column
788 | if (!e[config.sortMultiSortKey]) {
789 | // flush the sort list
790 | config.sortList = [];
791 | if (config.sortForce != null) {
792 | var a = config.sortForce;
793 | for (var j = 0; j < a.length; j++) {
794 | if (a[j][0] != i) {
795 | config.sortList.push(a[j]);
796 | }
797 | }
798 | }
799 | // add column to sort list
800 | config.sortList.push([i, this.order]);
801 | // multi column sorting
802 | } else {
803 | // the user has clicked on an all
804 | // ready sortet column.
805 | if (isValueInArray(i, config.sortList)) {
806 | // revers the sorting direction
807 | // for all tables.
808 | for (var j = 0; j < config.sortList.length; j++) {
809 | var s = config.sortList[j],
810 | o = config.headerList[s[0]];
811 | if (s[0] == i) {
812 | o.count = s[1];
813 | o.count++;
814 | s[1] = o.count % 2;
815 | }
816 | }
817 | } else {
818 | // add column to sort list array
819 | config.sortList.push([i, this.order]);
820 | }
821 | }
822 | setTimeout(function () {
823 | // set css for headers
824 | setHeadersCss($this[0], $headers, config.sortList, sortCSS);
825 | appendToTable($this[0], multisort($this[0], config.sortList, cache));
826 | }, 1);
827 | // stop normal event by returning false
828 | return false;
829 | }
830 | // cancel selection
831 | })
832 | .mousedown(function () {
833 | if (config.cancelSelection) {
834 | this.onselectstart = function () {
835 | return false;
836 | };
837 | return false;
838 | }
839 | });
840 | // apply easy methods that trigger binded events
841 | $this
842 | .bind("update", function () {
843 | var me = this;
844 | setTimeout(function () {
845 | // rebuild parsers.
846 | me.config.parsers = buildParserCache(me, $headers);
847 | // rebuild the cache map
848 | cache = buildCache(me);
849 | }, 1);
850 | })
851 | .bind("updateCell", function (e, cell) {
852 | var config = this.config;
853 | // get position from the dom.
854 | var pos = [cell.parentNode.rowIndex - 1, cell.cellIndex];
855 | // update cache
856 | cache.normalized[pos[0]][pos[1]] = config.parsers[pos[1]].format(getElementText(config, cell), cell);
857 | })
858 | .bind("sorton", function (e, list) {
859 | $(this).trigger("sortStart");
860 | config.sortList = list;
861 | // update and store the sortlist
862 | var sortList = config.sortList;
863 | // update header count index
864 | updateHeaderSortCount(this, sortList);
865 | // set css for headers
866 | setHeadersCss(this, $headers, sortList, sortCSS);
867 | // sort the table and append it to the dom
868 | appendToTable(this, multisort(this, sortList, cache));
869 | })
870 | .bind("appendCache", function () {
871 | appendToTable(this, cache);
872 | })
873 | .bind("applyWidgetId", function (e, id) {
874 | getWidgetById(id).format(this);
875 | })
876 | .bind("applyWidgets", function () {
877 | // apply widgets
878 | applyWidget(this);
879 | });
880 | if ($.metadata && $(this).metadata() && $(this).metadata().sortlist) {
881 | config.sortList = $(this).metadata().sortlist;
882 | }
883 | // if user has supplied a sort list to constructor.
884 | if (config.sortList.length > 0) {
885 | $this.trigger("sorton", [config.sortList]);
886 | }
887 | // apply widgets
888 | applyWidget(this);
889 | });
890 | };
891 | this.addParser = function (parser) {
892 | var l = parsers.length,
893 | a = true;
894 | for (var i = 0; i < l; i++) {
895 | if (parsers[i].id.toLowerCase() == parser.id.toLowerCase()) {
896 | a = false;
897 | }
898 | }
899 | if (a) {
900 | parsers.push(parser);
901 | }
902 | };
903 | this.addWidget = function (widget) {
904 | widgets.push(widget);
905 | };
906 | this.formatFloat = function (s) {
907 | var i = parseFloat(s);
908 | return isNaN(i) ? 0 : i;
909 | };
910 | this.formatInt = function (s) {
911 | var i = parseInt(s);
912 | return isNaN(i) ? 0 : i;
913 | };
914 | this.isDigit = function (s, config) {
915 | // replace all an wanted chars and match.
916 | return /^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g, "")));
917 | };
918 | this.clearTableBody = function (table) {
919 | if ($.browser.msie) {
920 | while (table.tBodies[0].firstChild) {
921 | table.tBodies[0].removeChild(table.tBodies[0].firstChild);
922 | }
923 | } else {
924 | table.tBodies[0].innerHTML = "";
925 | }
926 | };
927 | })(),
928 | });
929 |
930 | // extend plugin scope
931 | $.fn.extend({
932 | tablesorter: $.tablesorter.construct,
933 | });
934 |
935 | // make shortcut
936 | var ts = $.tablesorter;
937 |
938 | // add default parsers
939 | ts.addParser({
940 | id: "text",
941 | is: function (s) {
942 | return true;
943 | },
944 | format: function (s) {
945 | return $.trim(s.toLocaleLowerCase());
946 | },
947 | type: "text",
948 | });
949 |
950 | ts.addParser({
951 | id: "digit",
952 | is: function (s, table) {
953 | var c = table.config;
954 | return $.tablesorter.isDigit(s, c);
955 | },
956 | format: function (s) {
957 | return $.tablesorter.formatFloat(s);
958 | },
959 | type: "numeric",
960 | });
961 |
962 | ts.addParser({
963 | id: "currency",
964 | is: function (s) {
965 | return /^[£$€?.]/.test(s);
966 | },
967 | format: function (s) {
968 | return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g), ""));
969 | },
970 | type: "numeric",
971 | });
972 |
973 | ts.addParser({
974 | id: "ipAddress",
975 | is: function (s) {
976 | return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);
977 | },
978 | format: function (s) {
979 | var a = s.split("."),
980 | r = "",
981 | l = a.length;
982 | for (var i = 0; i < l; i++) {
983 | var item = a[i];
984 | if (item.length == 2) {
985 | r += "0" + item;
986 | } else {
987 | r += item;
988 | }
989 | }
990 | return $.tablesorter.formatFloat(r);
991 | },
992 | type: "numeric",
993 | });
994 |
995 | ts.addParser({
996 | id: "url",
997 | is: function (s) {
998 | return /^(https?|ftp|file):\/\/$/.test(s);
999 | },
1000 | format: function (s) {
1001 | return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//), ""));
1002 | },
1003 | type: "text",
1004 | });
1005 |
1006 | ts.addParser({
1007 | id: "isoDate",
1008 | is: function (s) {
1009 | return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);
1010 | },
1011 | format: function (s) {
1012 | return $.tablesorter.formatFloat(s != "" ? new Date(s.replace(new RegExp(/-/g), "/")).getTime() : "0");
1013 | },
1014 | type: "numeric",
1015 | });
1016 |
1017 | ts.addParser({
1018 | id: "percent",
1019 | is: function (s) {
1020 | return /\%$/.test($.trim(s));
1021 | },
1022 | format: function (s) {
1023 | return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g), ""));
1024 | },
1025 | type: "numeric",
1026 | });
1027 |
1028 | ts.addParser({
1029 | id: "usLongDate",
1030 | is: function (s) {
1031 | return s.match(
1032 | new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/)
1033 | );
1034 | },
1035 | format: function (s) {
1036 | return $.tablesorter.formatFloat(new Date(s).getTime());
1037 | },
1038 | type: "numeric",
1039 | });
1040 |
1041 | ts.addParser({
1042 | id: "shortDate",
1043 | is: function (s) {
1044 | return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);
1045 | },
1046 | format: function (s, table) {
1047 | var c = table.config;
1048 | s = s.replace(/\-/g, "/");
1049 | if (c.dateFormat == "us") {
1050 | // reformat the string in ISO format
1051 | s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2");
1052 | }
1053 | if (c.dateFormat == "pt") {
1054 | s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1");
1055 | } else if (c.dateFormat == "uk") {
1056 | // reformat the string in ISO format
1057 | s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1");
1058 | } else if (c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") {
1059 | s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, "$1/$2/$3");
1060 | }
1061 | return $.tablesorter.formatFloat(new Date(s).getTime());
1062 | },
1063 | type: "numeric",
1064 | });
1065 | ts.addParser({
1066 | id: "time",
1067 | is: function (s) {
1068 | return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);
1069 | },
1070 | format: function (s) {
1071 | return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime());
1072 | },
1073 | type: "numeric",
1074 | });
1075 | ts.addParser({
1076 | id: "metadata",
1077 | is: function (s) {
1078 | return false;
1079 | },
1080 | format: function (s, table, cell) {
1081 | var c = table.config,
1082 | p = !c.parserMetadataName ? "sortValue" : c.parserMetadataName;
1083 | return $(cell).metadata()[p];
1084 | },
1085 | type: "numeric",
1086 | });
1087 | // add default widgets
1088 | ts.addWidget({
1089 | id: "zebra",
1090 | format: function (table) {
1091 | if (table.config.debug) {
1092 | var time = new Date();
1093 | }
1094 | var $tr,
1095 | row = -1,
1096 | odd;
1097 | // loop through the visible rows
1098 | $("tr:visible", table.tBodies[0]).each(function (i) {
1099 | $tr = $(this);
1100 | // style children rows the same way the parent
1101 | // row was styled
1102 | if (!$tr.hasClass(table.config.cssChildRow)) row++;
1103 | odd = row % 2 == 0;
1104 | $tr.removeClass(table.config.widgetZebra.css[odd ? 0 : 1]).addClass(table.config.widgetZebra.css[odd ? 1 : 0]);
1105 | });
1106 | if (table.config.debug) {
1107 | $.tablesorter.benchmark("Applying Zebra widget", time);
1108 | }
1109 | },
1110 | });
1111 | })(jQuery);
1112 |
--------------------------------------------------------------------------------
/src/components/Form.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import axios from "axios";
4 | import _ from "lodash";
5 | import queryString from "query-string";
6 | import { ToastContainer, toast } from "react-toastify";
7 | import "react-toastify/dist/ReactToastify.css";
8 | import Harvester from "./Harvester";
9 | import { capitalizeFirstLetter, backend } from "../util";
10 |
11 | class Form extends React.Component {
12 | constructor(props) {
13 | super(props);
14 | this.state = {
15 | siteid: "en",
16 | project: "wikipedia",
17 | namespace: 0,
18 | p: 1,
19 | template: "",
20 | templateredirects: [],
21 | parameters: [""],
22 | pagetitle: false,
23 | limityear: 1926,
24 | rel: "geq",
25 | decimalmark: ".",
26 | category: "",
27 | depth: 1,
28 | manuallist: "",
29 | alreadyset: true,
30 | wikisyntax: true,
31 | errors: [],
32 | allowedunits: [],
33 | constraints: {},
34 | addprefix: "",
35 | addsuffix: "",
36 | removeprefix: "",
37 | removesuffix: "",
38 | searchvalue: "",
39 | replacevalue: "",
40 | monolanguage: "",
41 | calendar: "Q1985727",
42 | ready: {
43 | siteinfo: false,
44 | pages: false,
45 | templateredirects: false,
46 | categorymembers: true,
47 | propertyinfo: false,
48 | constraints: false,
49 | itemswithproperty: false,
50 | buttonPressed: false,
51 | },
52 | };
53 | this.handleInputChange = this.handleInputChange.bind(this);
54 | this.handleSubmit = this.handleSubmit.bind(this);
55 | this.handleFocus = this.handleFocus.bind(this);
56 | this.loadSiteinfo = this.loadSiteinfo.bind(this);
57 | this.loadPages = this.loadPages.bind(this);
58 | this.loadTemplateredirects = this.loadTemplateredirects.bind(this);
59 | this.loadCategorymembers = this.loadCategorymembers.bind(this);
60 | this.loadPropertyinfo = this.loadPropertyinfo.bind(this);
61 | this.loadItemsWithProperty = this.loadItemsWithProperty.bind(this);
62 | this.loadConstraints = this.loadConstraints.bind(this);
63 | this.loadUnits = this.loadUnits.bind(this);
64 | this.markError = this.markError.bind(this);
65 | this.addAlias = this.addAlias.bind(this);
66 | this.markReady = this.markReady.bind(this);
67 | this.markUnready = this.markUnready.bind(this);
68 | this.prepareHarvester = this.prepareHarvester.bind(this);
69 | this.preloadForm = this.preloadForm.bind(this);
70 | this.oldVals = { p: 1 };
71 | this.candidates = [];
72 | this.categorymembers = [];
73 | this.itemswithproperty = [];
74 | this.job = {};
75 | this.tokenC = axios.CancelToken.source();
76 | this.tokenP = axios.CancelToken.source();
77 | this.tokenS = axios.CancelToken.source();
78 | this.tokenT = axios.CancelToken.source();
79 | }
80 |
81 | preloadForm(params, load) {
82 | let stringvariables = [
83 | "siteid",
84 | "project",
85 | "namespace",
86 | "template",
87 | "addprefix",
88 | "removeprefix",
89 | "addsuffix",
90 | "removesuffix",
91 | "searchvalue",
92 | "replacevalue",
93 | "category",
94 | "depth",
95 | "calendar",
96 | "limityear",
97 | "rel",
98 | "unit",
99 | "decimalmark",
100 | "manuallist",
101 | "monolanguage",
102 | ];
103 | let arrayvariables = ["parameters", "templateredirects"];
104 | let booleanvariables = ["wikisyntax", "alreadyset", "pagetitle"];
105 | let update = {};
106 | for (let [key, value] of Object.entries(params)) {
107 | if (key === "p") {
108 | update[key] = value.replace("P", "");
109 | } else if (key === "constraints") {
110 | update.constraint_temp = value.split("|");
111 | } else if (key === "templateredirects") {
112 | update.templateredirects_temp = value.split("|");
113 | } else if (booleanvariables.includes(key)) {
114 | update[key] = value === "1";
115 | } else if (stringvariables.includes(key)) {
116 | update[key] = value;
117 | } else if (arrayvariables.includes(key)) {
118 | update[key] = value.split("|");
119 | }
120 | }
121 | this.setState(update, () => {
122 | this.handleFocus();
123 | if (load) {
124 | this.markReady("buttonPressed");
125 | }
126 | });
127 | }
128 |
129 | componentDidMount() {
130 | let params = queryString.parse(window.location.search);
131 | if (Object.keys(params).length > 0) {
132 | if ("htid" in params) {
133 | this.job.htid = params.htid;
134 | axios
135 | .get("https://pltools.toolforge.org/harvesttemplates/gethtshare.php", {
136 | params,
137 | })
138 | .then(response => {
139 | this.preloadForm(response.data, true);
140 | })
141 | .catch(error => {
142 | console.log(error);
143 | });
144 | } else {
145 | this.preloadForm(params, false);
146 | }
147 | }
148 | }
149 |
150 | prepareHarvester() {
151 | let fcandidates = _.differenceBy(this.candidates, this.itemswithproperty, "qid");
152 | if (this.categorymembers.length > 0) {
153 | fcandidates = fcandidates.filter(c => this.categorymembers.includes(c.title));
154 | }
155 | if (this.state.manuallist !== "") {
156 | let manuallist = this.state.manuallist.split("\n").map(e => e.replace(/_/g, " ").trim());
157 | let fcandidates1 = fcandidates.filter(c => manuallist.includes(c.title));
158 | let fcandidates2 = fcandidates.filter(c => manuallist.includes(c.qid));
159 | fcandidates = fcandidates1.concat(fcandidates2);
160 | this.job.manuallist = this.state.manuallist;
161 | }
162 | fcandidates.sort((a, b) => a.timestamp - b.timestamp);
163 | this.job.editgroup = Math.floor(Math.random() * Math.pow(2, 48)).toString(16);
164 | this.job.addprefix = this.state.addprefix;
165 | this.job.removeprefix = this.state.removeprefix;
166 | this.job.addsuffix = this.state.addsuffix;
167 | this.job.removesuffix = this.state.removesuffix;
168 | this.job.searchvalue = this.state.searchvalue;
169 | this.job.replacevalue = this.state.replacevalue;
170 | this.job.namespace = this.state.namespace;
171 | this.job.template = capitalizeFirstLetter(this.state.template).replace(/_/g, " ");
172 | this.job.parameters = this.state.parameters;
173 | this.job.pagetitle = this.state.pagetitle;
174 | this.job.calendar = this.state.calendar;
175 | this.job.limityear = this.state.limityear;
176 | this.job.rel = this.state.rel;
177 | this.job.siteid = this.state.siteid;
178 | this.job.project = this.state.project;
179 | this.job.unit = this.state.unit;
180 | this.job.decimalmark = this.state.decimalmark;
181 | this.job.category = this.state.category;
182 | this.job.depth = this.state.depth;
183 | this.job.alreadyset = this.state.alreadyset;
184 | this.job.wikisyntax = this.state.wikisyntax;
185 | this.job.monolanguage = this.state.monolanguage;
186 | this.job.constraints = [];
187 | for (let c of Object.values(this.state.constraints)) {
188 | if (c.value === true) {
189 | this.job.constraints.push(c.qid);
190 | }
191 | }
192 | this.job.templateredirects = [];
193 | for (let c of Object.values(this.state.templateredirects)) {
194 | if (c.value === true) {
195 | this.job.templateredirects.push(c.title);
196 | }
197 | }
198 |
199 | ReactDOM.render(, document.getElementById("harvester"));
200 |
201 | this.markUnready("buttonPressed");
202 | }
203 |
204 | markReady(value) {
205 | let ready = this.state.ready;
206 | ready[value] = true;
207 | this.setState({
208 | ready: ready,
209 | });
210 | for (let val of Object.values(this.state.ready)) {
211 | if (val === false) {
212 | return 0;
213 | }
214 | }
215 | this.prepareHarvester();
216 | }
217 |
218 | markUnready(value) {
219 | let ready = this.state.ready;
220 | ready[value] = false;
221 | this.setState({
222 | ready: ready,
223 | });
224 | }
225 |
226 | markError(field) {
227 | this.markUnready("buttonPressed");
228 | let newerrors = this.state.errors;
229 | newerrors.push(field);
230 | this.setState({
231 | errors: newerrors,
232 | });
233 | }
234 |
235 | loadItemsWithProperty() {
236 | let data = {
237 | query: `SELECT ?item { ?item wdt:P${this.state.p} [] }`, //better but slower: p/ps
238 | format: "json",
239 | };
240 | axios
241 | .get("https://query.wikidata.org/bigdata/namespace/wdq/sparql?", {
242 | params: data,
243 | })
244 | .then(response => {
245 | this.itemswithproperty = response.data.results.bindings.map(x => ({
246 | qid: x.item.value.replace("http://www.wikidata.org/entity/", ""),
247 | }));
248 | this.markReady("itemswithproperty");
249 | })
250 | .catch(error => {
251 | console.log("error loadItemsWithProperty", error, data.query);
252 | if (!axios.isCancel(error)) {
253 | this.markError("alreadyset");
254 | }
255 | });
256 | }
257 |
258 | loadUnits(allowedunits_id) {
259 | let allowedunits = [];
260 | if (allowedunits_id.length > 0) {
261 | if (allowedunits_id.includes("1")) {
262 | allowedunits.push(
263 |
266 | );
267 | allowedunits_id = allowedunits_id.filter(item => item !== "1");
268 | }
269 | let unit = "1";
270 | let data = {
271 | action: "wbgetentities",
272 | ids: allowedunits_id.join("|"),
273 | props: "labels",
274 | languages: "en",
275 | format: "json",
276 | origin: "*",
277 | };
278 | axios
279 | .get("https://www.wikidata.org/w/api.php", {
280 | params: data,
281 | cancelToken: this.tokenP.token,
282 | })
283 | .then(response => {
284 | if ("entities" in response.data) {
285 | for (let q of Object.values(response.data.entities)) {
286 | if (unit === "1") {
287 | unit = q.id;
288 | }
289 | if ("en" in q.labels) {
290 | allowedunits.push(
291 |
294 | );
295 | } else {
296 | allowedunits.push(
297 |
300 | );
301 | }
302 | }
303 | }
304 | this.setState({
305 | allowedunits: allowedunits,
306 | });
307 | if (this.state.unit === undefined) {
308 | this.setState({
309 | unit: unit,
310 | });
311 | }
312 | this.markReady("propertyinfo");
313 | })
314 | .catch(error => {
315 | console.log(error);
316 | });
317 | } else {
318 | toast.error(allowed unit constraint on property page missing, { position: toast.POSITION.TOP_CENTER });
319 | this.markError("property");
320 | }
321 | }
322 |
323 | loadConstraints(constraints_id, constraints_mandatory_id) {
324 | let constraints = {};
325 | let data = {
326 | action: "wbgetentities",
327 | ids: constraints_id.concat(constraints_mandatory_id).join("|"),
328 | props: "labels",
329 | languages: "en",
330 | format: "json",
331 | origin: "*",
332 | };
333 | axios
334 | .get("https://www.wikidata.org/w/api.php", {
335 | params: data,
336 | cancelToken: this.tokenP.token,
337 | })
338 | .then(response => {
339 | if ("entities" in response.data) {
340 | for (let q of Object.values(response.data.entities)) {
341 | let label = q.id;
342 | if ("en" in q.labels) {
343 | label = q.labels.en.value;
344 | }
345 | if (constraints_mandatory_id.includes(q.id)) {
346 | constraints[q.id] = { qid: q.id, label: label, disabled: true, value: true };
347 | } else if (this.state.constraint_temp) {
348 | constraints[q.id] = { qid: q.id, label: label, disabled: false, value: this.state.constraint_temp.includes(q.id) };
349 | } else {
350 | constraints[q.id] = { qid: q.id, label: label, disabled: false, value: true };
351 | }
352 | }
353 | }
354 | this.setState({
355 | constraints: constraints,
356 | });
357 | this.markReady("constraints");
358 | })
359 | .catch(error => {
360 | console.log(error);
361 | });
362 | }
363 |
364 | loadPropertyinfo() {
365 | this.job.p = `P${this.state.p}`;
366 | let data = {
367 | action: "wbgetentities",
368 | ids: this.job.p,
369 | props: "claims|datatype|labels",
370 | languages: "en",
371 | format: "json",
372 | origin: "*",
373 | };
374 | axios
375 | .get("https://www.wikidata.org/w/api.php", {
376 | params: data,
377 | cancelToken: this.tokenP.token,
378 | })
379 | .then(response => {
380 | if (!("missing" in response.data.entities[this.job.p])) {
381 | if ("P31" in response.data.entities[this.job.p].claims) {
382 | for (let claim of response.data.entities[this.job.p].claims.P31) {
383 | let instance = claim.mainsnak.datavalue.value.id;
384 | if (instance === "Q37911748" || instance === "Q18644427") {
385 | toast.error(Property is deprecated, { position: toast.POSITION.TOP_CENTER });
386 | this.markError("property");
387 | return 0;
388 | }
389 | }
390 | }
391 | this.job.datatype = response.data.entities[this.job.p].datatype;
392 | const supportedDatatypes = [
393 | "quantity",
394 | "time",
395 | "wikibase-item",
396 | "url",
397 | "string",
398 | "external-id",
399 | "commonsMedia",
400 | "monolingualtext",
401 | ];
402 | if (!supportedDatatypes.includes(this.job.datatype)) {
403 | toast.error(not supported datatype: {this.job.datatype}, { position: toast.POSITION.TOP_CENTER });
404 | this.markError("property");
405 | return 0;
406 | }
407 |
408 | let label = "en" in response.data.entities[this.job.p].labels ? response.data.entities[this.job.p].labels.en.value : this.job.p;
409 | let propinfofield = (
410 |
411 | {label}
412 |
413 | );
414 | this.setState({
415 | propinfofield: propinfofield,
416 | datatype: this.job.datatype,
417 | });
418 | let allowedunits_id = [];
419 | let constraints_id = [];
420 | let constraints_mandatory_id = [];
421 | if ("P2302" in response.data.entities[this.job.p].claims) {
422 | for (let claim of response.data.entities[this.job.p].claims.P2302) {
423 | if (claim.mainsnak.datavalue.value.id === "Q21514353") {
424 | for (let c of claim.qualifiers.P2305) {
425 | if (c.snaktype === "novalue") {
426 | allowedunits_id.push("1");
427 | } else if (c.snaktype === "value") {
428 | allowedunits_id.push(c.datavalue.value.id);
429 | }
430 | }
431 | }
432 | let cstatus = "normal";
433 | if ("qualifiers" in claim && "P2316" in claim.qualifiers) {
434 | for (let c of claim.qualifiers.P2316) {
435 | if (c.datavalue.value.id === "Q21502408") {
436 | cstatus = "mandatory";
437 | } else if (c.datavalue.value.id === "Q62026391") {
438 | cstatus = "suggestion";
439 | }
440 | }
441 | }
442 | if (cstatus === "mandatory") {
443 | constraints_mandatory_id.push(claim.mainsnak.datavalue.value.id);
444 | } else if (cstatus === "normal") {
445 | constraints_id.push(claim.mainsnak.datavalue.value.id);
446 | }
447 | }
448 | }
449 | this.loadConstraints(constraints_id, constraints_mandatory_id);
450 |
451 | if (response.data.entities[this.job.p].datatype === "quantity") {
452 | this.loadUnits(allowedunits_id);
453 | } else {
454 | this.markReady("propertyinfo");
455 | }
456 | } else {
457 | this.markError("property");
458 | }
459 | })
460 | .catch(error => {
461 | if (!axios.isCancel(error)) {
462 | console.log(error);
463 | }
464 | });
465 | }
466 |
467 | loadCategorymembers() {
468 | const qs = {
469 | category: this.state.category,
470 | depth: this.state.depth,
471 | namespace: this.state.namespace,
472 | servername: `${this.state.siteid}.${this.state.project}.org`,
473 | };
474 | axios
475 | .get(`${backend}categoryscan`, { params: qs })
476 | .then(response => {
477 | this.categorymembers = response.data;
478 | this.markReady("categorymembers");
479 | })
480 | .catch(error => {
481 | if (!axios.isCancel(error)) {
482 | console.log(error);
483 | this.markError("category");
484 | }
485 | });
486 | }
487 |
488 | loadTemplateredirects() {
489 | let templateredirects = {};
490 | let data = {
491 | action: "query",
492 | prop: "redirects",
493 | titles: `Template:${this.state.template}`,
494 | rdnamespace: 10,
495 | rdlimit: "max",
496 | format: "json",
497 | origin: "*",
498 | };
499 | axios
500 | .get(`${this.job.site}/w/api.php`, {
501 | params: data,
502 | cancelToken: this.tokenT.token,
503 | })
504 | .then(response => {
505 | for (let pa of Object.values(response.data.query.pages)) {
506 | if ("redirects" in pa) {
507 | for (let val of pa.redirects) {
508 | val.title = val.title.split(":")[1];
509 | if (this.state.templateredirects_temp) {
510 | templateredirects[val.pageid] = {
511 | title: val.title,
512 | value: this.state.templateredirects_temp.includes(val.title),
513 | pageid: val.pageid,
514 | };
515 | } else {
516 | templateredirects[val.pageid] = { title: val.title, value: true, pageid: val.pageid };
517 | }
518 | }
519 | }
520 | }
521 | this.setState({
522 | templateredirects: templateredirects,
523 | });
524 | this.markReady("templateredirects");
525 | })
526 | .catch(error => {
527 | if (!axios.isCancel(error)) {
528 | console.log(error);
529 | this.markError("template");
530 | }
531 | });
532 | }
533 |
534 | loadPages(cont = 0) {
535 | let templateinfofield;
536 | if (this.state.template !== "") {
537 | templateinfofield = (
538 |
543 | link
544 |
545 | );
546 | } else {
547 | templateinfofield = "";
548 | }
549 | this.setState({
550 | templateinfofield: templateinfofield,
551 | });
552 | let data = {
553 | action: "query",
554 | generator: "transcludedin",
555 | titles: `Template:${this.state.template}`,
556 | gtilimit: "max",
557 | gtinamespace: this.state.namespace,
558 | prop: "pageprops|revisions",
559 | rvprop: "timestamp",
560 | ppprop: "wikibase_item",
561 | gticontinue: cont,
562 | format: "json",
563 | origin: "*",
564 | };
565 | axios
566 | .get(`${this.job.site}/w/api.php`, {
567 | params: data,
568 | cancelToken: this.tokenT.token,
569 | })
570 | .then(response => {
571 | if ("query" in response.data) {
572 | for (let val of Object.values(response.data.query.pages)) {
573 | if ("pageprops" in val && "wikibase_item" in val.pageprops) {
574 | this.candidates.push({
575 | pageid: val.pageid,
576 | title: val.title,
577 | qid: val.pageprops.wikibase_item,
578 | lastedit: val.revisions[0].timestamp,
579 | });
580 | } else {
581 | this.candidates.push({
582 | pageid: val.pageid,
583 | title: val.title,
584 | lastedit: val.revisions[0].timestamp,
585 | });
586 | }
587 | }
588 | if ("continue" in response.data) {
589 | let cont = response.data.continue.gticontinue;
590 | this.loadPages(cont);
591 | } else {
592 | this.markReady("pages");
593 | }
594 | }
595 | })
596 | .catch(error => {
597 | if (!axios.isCancel(error)) {
598 | console.log(error);
599 | this.markError("template");
600 | }
601 | });
602 | }
603 |
604 | loadSiteinfo() {
605 | this.job.site = `https://${this.state.siteid}.${this.state.project}.org`;
606 | let data = {
607 | action: "query",
608 | meta: "siteinfo",
609 | siprop: "general|namespaces|namespacealiases",
610 | format: "json",
611 | origin: "*",
612 | };
613 | axios
614 | .get(`${this.job.site}/w/api.php`, {
615 | params: data,
616 | cancelToken: this.tokenS.token,
617 | })
618 | .then(response => {
619 | this.job.lang = response.data.query.general.lang;
620 | this.job.dbname = response.data.query.general.wikiid;
621 | let data = {
622 | query: `SELECT ?wiki { ?wiki wdt:P1800 '${this.job.dbname}'}`,
623 | format: "json",
624 | };
625 | axios
626 | .get("https://query.wikidata.org/bigdata/namespace/wdq/sparql?", {
627 | params: data,
628 | })
629 | .then(response => {
630 | if (response.data.results.bindings.length > 0) {
631 | this.job.wbeditionid = response.data.results.bindings[0].wiki.value.replace("http://www.wikidata.org/entity/", "");
632 | this.markReady("siteinfo");
633 | } else {
634 | this.markError("siteid");
635 | this.markError("project");
636 | }
637 | })
638 | .catch(error => console.error(error));
639 |
640 | let namespaces = {};
641 | for (var ns in response.data.query.namespaces) {
642 | namespaces[ns] = response.data.query.namespaces[ns]["*"];
643 | }
644 | this.job.fileprefixes = ["File", namespaces[6]];
645 | this.job.templateprefixes = ["Template", namespaces[10]];
646 | for (let i in response.data.query.namespacealiases) {
647 | if (response.data.query.namespacealiases[i].id === 6) {
648 | this.job.fileprefixes.push(response.data.query.namespacealiases[i]["*"]);
649 | } else if (response.data.query.namespacealiases[i].id === 10) {
650 | this.job.templateprefixes.push(response.data.query.namespacealiases[i]["*"]);
651 | }
652 | }
653 | })
654 | .catch(error => {
655 | if (!axios.isCancel(error)) {
656 | this.markError("siteid");
657 | this.markError("project");
658 | }
659 | });
660 | }
661 |
662 | addAlias(event) {
663 | event.preventDefault();
664 | let newparameters = this.state.parameters;
665 | newparameters.push("");
666 | this.setState({
667 | parameters: newparameters,
668 | });
669 | }
670 |
671 | handleSubmit(event) {
672 | event.preventDefault();
673 | this.handleFocus();
674 | this.job.htid = undefined;
675 | if (!this.state.parameters[0] && !this.state.aparameter1 && !this.state.pagetitle) {
676 | this.markError("parameters");
677 | } else if (this.state.template === "") {
678 | this.markError("template");
679 | } else if (this.state.siteid === "") {
680 | this.markError("siteid");
681 | } else if (this.state.p === 1) {
682 | this.markError("property");
683 | } else {
684 | ReactDOM.render(, document.getElementById("harvester"));
685 | setTimeout(() => {
686 | this.markReady("buttonPressed");
687 | }, 1000);
688 | }
689 | }
690 |
691 | handleInputChange(event) {
692 | this.markUnready("buttonPressed");
693 | const target = event.target;
694 | const name = target.name;
695 | let value;
696 | if (name === "parameters") {
697 | value = this.state.parameters;
698 | value[target.getAttribute("listid")] = target.value;
699 | } else if (name === "templateredirects") {
700 | value = this.state.templateredirects;
701 | value[target.getAttribute("listid")].value = target.checked;
702 | } else if (name === "constraints") {
703 | value = this.state.constraints;
704 | value[target.getAttribute("listid")].value = target.checked;
705 | } else if (target.type === "checkbox") {
706 | value = target.checked;
707 | } else {
708 | value = target.value;
709 | }
710 | let newerrors = this.state.errors.filter(e => e !== name);
711 | if (name === "siteid") {
712 | newerrors = newerrors.filter(e => e !== "project");
713 | } else if (name === "project") {
714 | newerrors = newerrors.filter(e => e !== "siteid");
715 | } else if (name === "pagetitle") {
716 | newerrors = newerrors.filter(e => e !== "parameters");
717 | }
718 | this.setState({
719 | [name]: value,
720 | errors: newerrors,
721 | });
722 | }
723 |
724 | handleFocus() {
725 | if (this.oldVals.siteid !== this.state.siteid || this.oldVals.project !== this.state.project) {
726 | this.oldVals.siteid = this.state.siteid;
727 | this.oldVals.project = this.state.project;
728 | this.oldVals.template = ""; //triggers loadPages()
729 | this.oldVals.category = ""; //triggers loadCategorymembers()
730 | this.tokenS.cancel("Operation canceled due to input changes");
731 | this.tokenS = axios.CancelToken.source();
732 | this.markUnready("siteinfo");
733 | this.loadSiteinfo();
734 | }
735 | if (this.oldVals.template !== this.state.template || this.oldVals.namespace !== this.state.namespace) {
736 | this.candidates = [];
737 | this.oldVals.template = this.state.template;
738 | this.oldVals.namespace = this.state.namespace;
739 | this.tokenT.cancel("Operation canceled due to input changes");
740 | this.tokenT = axios.CancelToken.source();
741 | this.markUnready("pages");
742 | this.markUnready("templateredirects");
743 | this.loadPages();
744 | this.loadTemplateredirects();
745 | }
746 | if (this.oldVals.p !== this.state.p || this.oldVals.alreadyset !== this.state.alreadyset) {
747 | this.itemswithproperty = [];
748 | this.tokenP.cancel("Operation canceled due to input changes");
749 | this.tokenP = axios.CancelToken.source();
750 | this.oldVals.alreadyset = this.state.alreadyset;
751 | if (this.oldVals.p !== this.state.p) {
752 | this.oldVals.p = this.state.p;
753 | this.markUnready("constraints");
754 | this.markUnready("propertyinfo");
755 | this.loadPropertyinfo();
756 | }
757 | if (this.state.alreadyset === true) {
758 | this.markUnready("itemswithproperty");
759 | this.loadItemsWithProperty();
760 | } else {
761 | this.markReady("itemswithproperty");
762 | }
763 | }
764 | if (this.oldVals.category !== this.state.category || this.oldVals.depth !== this.state.depth) {
765 | this.categorymembers = [];
766 | this.oldVals.category = this.state.category;
767 | this.oldVals.depth = this.state.depth;
768 | this.tokenC.cancel("Operation canceled due to input changes");
769 | this.tokenC = axios.CancelToken.source();
770 | if (this.state.category.length > 0) {
771 | this.markUnready("categorymembers");
772 | this.loadCategorymembers();
773 | }
774 | }
775 | }
776 |
777 | render() {
778 | let standardfield = [];
779 | for (let i = 0; i < this.state.parameters.length; i += 1) {
780 | standardfield.push(
781 |
791 | );
792 | }
793 | let mainfield = (
794 |
795 | {standardfield}
796 |
797 |
800 |
801 | );
802 | let parameterfields;
803 | switch (this.state.datatype) {
804 | case "wikibase-item":
805 | parameterfields = (
806 |
807 | {mainfield}
808 |
815 | try to match target page even without wikisyntax
816 |
817 | );
818 | break;
819 | case "time":
820 | parameterfields = (
821 |
822 | {mainfield}or
823 |
824 | {" "}
832 | year
833 |
834 | {" "}
842 | month
843 |
844 | {" "}
852 | day
853 |
854 | {" "}
858 | if year
859 |
863 |
871 |
872 | );
873 | break;
874 | case "quantity":
875 | parameterfields = (
876 |
877 | {mainfield}
878 |
879 | unit{" "}
880 |
883 |
884 | decimal mark
885 |
889 |
890 | );
891 | break;
892 | case "monolingualtext":
893 | parameterfields = (
894 |
895 | {mainfield}
896 |
897 |
904 | or use page title
905 |
906 | language code
907 |
915 |
916 | );
917 | break;
918 | default:
919 | parameterfields = mainfield;
920 | }
921 |
922 | let constraintfield;
923 | if (Object.values(this.state.constraints).length > 0) {
924 | let constraintboxes = [];
925 | for (let c of Object.values(this.state.constraints)) {
926 | constraintboxes.push(
927 |
928 |
929 |
939 | {c.label}
940 |
941 |
942 | );
943 | }
944 | constraintfield = (
945 |
946 |
Check quality
947 | {constraintboxes}
948 |
949 | );
950 | }
951 | let templateredirectfield;
952 | if (Object.values(this.state.templateredirects).length > 0) {
953 | let templateredirectboxes = [];
954 | for (let c of Object.values(this.state.templateredirects)) {
955 | templateredirectboxes.push(
956 |
957 |
966 | {c.title}
967 |
968 | );
969 | }
970 | templateredirectfield = (
971 |
972 |
include
973 |
{templateredirectboxes}
974 |
975 | );
976 | }
977 |
978 | return (
979 |
1211 | );
1212 | }
1213 | }
1214 |
1215 | export default Form;
1216 |
--------------------------------------------------------------------------------
/src/fonts/roboto-v20-latin-regular.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
309 |
--------------------------------------------------------------------------------
/src/fonts/roboto-v20-latin-300.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
313 |
--------------------------------------------------------------------------------