diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..d5582db
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,2 @@
+# exclude dev directory from container
+dev
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 0000000..6566ecb
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,13 @@
+{
+ "root": true,
+ "parser": "@babel/eslint-parser",
+ "parserOptions": {
+ "requireConfigFile": false,
+ "babelOptions": {
+ "babelrc": false,
+ "configFile": false,
+ "presets": ["@babel/preset-env"]
+ }
+ },
+ "extends": ["plugin:prettier/recommended"]
+}
diff --git a/.gitignore b/.gitignore
index ce4844d..eb0fb2f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
*~
.\#*
+node_modules
+templates_c
vendor
-templates_c
\ No newline at end of file
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 0000000..c83793c
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,11 @@
+{
+ "printWidth": 80,
+ "tabWidth": 2,
+ "singleQuote": false,
+ "trailingComma": "all",
+ "bracketSpacing": true,
+ "semi": true,
+ "useTabs": false,
+ "parser": "babel",
+ "bracketSameLine": false
+}
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..31662c0
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,19 @@
+# syntax=docker/dockerfile:experimental
+
+# use wordpress image as the base image
+FROM wordpress
+
+# install unzip for composer
+RUN apt-get update && apt-get install apt-utils zip unzip -y
+
+# Install Composer
+RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
+
+# copy all the files in this folder to plugins directory
+COPY . /var/www/html/wp-content/plugins/termination-of-transfer
+
+# allow root user so composer can install dependencies without having root user error
+RUN export COMPOSER_ALLOW_SUPERUSER=1;
+
+# cd to plugin directory AND install plugin dependencies
+RUN cd /var/www/html/wp-content/plugins/termination-of-transfer && composer install
diff --git a/assets/js/pdf.js b/assets/js/pdf.js
new file mode 100644
index 0000000..323b34e
--- /dev/null
+++ b/assets/js/pdf.js
@@ -0,0 +1,148 @@
+/*
+ Termination of Transfer - tool to help in returning authors rights.
+ Copyright (C) 2016 Creative Commons Corporation.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// PDF Generation
+// (browser-side data preparation and call to server)
+////////////////////////////////////////////////////////////////////////////////
+
+const TotPdf = {};
+
+TotPdf.url = `${jQuery("script[src*='/termination-of-transfer/dist/js/pdf.js']")
+ .attr("src")
+ .replace(/dist\/js\/pdf\.js.*$/, "")}pdf-result.php`;
+
+TotPdf.appendProperty = (details, key, value) => {
+ const mapping = { key: key, value: value };
+ details.push(mapping);
+};
+
+TotPdf.append203Windows = (details) => {
+ let notice = "";
+ let termination = "";
+
+ if (TotValues.notice_begin != undefined) {
+ notice += `${TotValues.notice_begin}-${TotValues.notice_end}`;
+ termination += `${TotValues.term_begin}-${TotValues.term_end}`;
+ }
+
+ if (TotValues.p_term_begin != undefined) {
+ if (notice != "") {
+ notice += " or ";
+ termination += " or ";
+ }
+ notice += `${TotValues.p_notice_begin}-${TotValues.p_notice_end}`;
+ termination += `${TotValues.p_term_begin}-${TotValues.p_term_end}`;
+ }
+
+ TotPdf.appendProperty(
+ details,
+ '§ 203 notice window',
+ notice,
+ );
+ TotPdf.appendProperty(
+ details,
+ '§ 203 termination window',
+ termination,
+ );
+};
+
+TotPdf.append304Windows = (details) => {
+ TotPdf.appendProperty(
+ details,
+ '§ 304(c) notice window begins',
+ TotValues.notice_begin,
+ );
+ TotPdf.appendProperty(
+ details,
+ '§ 304(c) notice window ends',
+ TotValues.notice_end,
+ );
+ TotPdf.appendProperty(
+ details,
+ '§ 304(c) termination window begins',
+ TotValues.term_begin,
+ );
+ TotPdf.appendProperty(
+ details,
+ '§ 304(c) termination window ends',
+ TotValues.term_end,
+ );
+ if (TotValues.d_notice_begin != undefined) {
+ TotPdf.appendProperty(
+ details,
+ '§ 304(d) notice window begins',
+ TotValues.d_notice_begin,
+ );
+ TotPdf.appendProperty(
+ details,
+ '§ 304(d) notice window ends',
+ TotValues.d_notice_end,
+ );
+ TotPdf.appendProperty(
+ details,
+ '§ 304(d) termination window begins',
+ TotValues.d_term_begin,
+ );
+ TotPdf.appendProperty(
+ details,
+ '§ 304(d) termination window ends',
+ TotValues.d_term_end,
+ );
+ }
+};
+
+TotPdf.appendWindows = (details) => {
+ if (TotRules.is203()) {
+ TotPdf.append203Windows(details);
+ } else if (TotRules.is304()) {
+ TotPdf.append304Windows(details);
+ }
+};
+
+TotPdf.details = () => {
+ let details = [];
+ Object.getOwnPropertyNames(totVarsToTitles).forEach((key) => {
+ if (TotValues[key] != undefined && TotValues[key] != "") {
+ TotPdf.appendProperty(details, totVarsToTitles[key], TotValues[key]);
+ }
+ });
+ TotPdf.appendWindows(details);
+ return details;
+};
+
+TotPdf.request = () => {
+ const data = {
+ report_timestamp: TotValues.current_date.getTime() / 1000,
+ flags: TotValues.flags.sort(), // Sorts inline & returns, so OK here
+ conclusion: TotValues.conclusion,
+ details: TotPdf.details(),
+ };
+ const totform = document.createElement("FORM");
+ totform.setAttribute("action", TotPdf.url);
+ totform.setAttribute("method", "post");
+ totform.setAttribute("enctype", "multipart/form-data");
+ totform.setAttribute("target", "_blank");
+ const data_field = document.createElement("INPUT");
+ data_field.setAttribute("type", "hidden");
+ data_field.setAttribute("name", "data");
+ data_field.setAttribute("value", JSON.stringify(data));
+ totform.appendChild(data_field);
+ jQuery("body").append(totform);
+ totform.submit();
+};
diff --git a/assets/js/questions.js b/assets/js/questions.js
new file mode 100644
index 0000000..041ca85
--- /dev/null
+++ b/assets/js/questions.js
@@ -0,0 +1,516 @@
+/*
+ Termination of Transfer - tool to help in returning authors rights.
+ Copyright (C) 2016 Creative Commons Corporation.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// Presentation of questions, and main flow of control
+// (This is slightly overloaded)
+////////////////////////////////////////////////////////////////////////////////
+
+const TotQuestions = {};
+
+////////////////////////////////////////////////////////////////////////////////
+// Section One
+////////////////////////////////////////////////////////////////////////////////
+
+// When was the work created?
+
+TotQuestions.s1q1a = {
+ section: 1,
+ question: "When was the work created?",
+ explanation:
+ "The year in which a work was created can affect its copyright status and its treatment under U.S. copyright law. Most importantly, the tool is concerned with whether a worked was made before or after January 1, 1978, when the most recent overhaul of U.S. copyright went into effect.",
+ variable: "creation_year",
+ input: "year",
+ pre: () => {
+ TotNavigation.disablePrevious();
+ TotNotifications.displayAnswersHint();
+ },
+ post: () => {
+ TotNotifications.removeAnswersHint();
+ },
+};
+
+// Has the work been published?
+
+TotQuestions.s1q1b = {
+ question: "Has the work been published?",
+ explanation:
+ 'Whether a work has been published can affect its copyright status and factor into the timing of a termination right. Note that "publication" has a particular meaning in U.S. copyright law, as discussed in our glossary.',
+ variable: "work_published",
+ input: "radio",
+ pre: () => {
+ TotNavigation.enablePrevious();
+ },
+};
+
+// When was the work first published?
+
+TotQuestions.s1q1bi = {
+ variable: "pub_year",
+ question: "When was the work first published?",
+ explanation:
+ 'When a work was published can affect its copyright status and factor into the timing of a termination right. Note that "publication" has a particular meaning in U.S. copyright law, as discussed in our glossary.',
+ input: "year",
+ validate: () => {
+ return (
+ TotValidation.validDate() ||
+ (parseInt(jQuery(".text-question").val()) < TotValues.creation_year
+ ? "The publication year cannot be earlier than the creation year."
+ : false)
+ );
+ },
+};
+
+// When was the work first published under the grant?
+
+TotQuestions.s1q1bii = {
+ section: 1,
+ question: "When was the work first published under the grant?",
+ explanation:
+ 'When a work was first published under the grant (which may be different than the the date the work was published for the first time) can factor into the timing of a termination right. Note that "publication" has a particular meaning in U.S. copyright law, as discussed in our glossary.',
+ variable: "grant_pub_year",
+ input: "year",
+ validate: () => {
+ let errors = TotValidation.validDate();
+ if (errors == false) {
+ const year = parseInt(jQuery(".text-question").val());
+ if (year < TotValues.creation_year) {
+ errors =
+ "Year of publication under grant cannot be earlier than year of creation.";
+ } else if (year < TotValues.pub_year) {
+ errors =
+ "Year of publication under grant cannot be earlier than year of initial publication.";
+ } /* else if (year < TotValues.k_year) {
+ errors = 'Year of publication under grant cannot be earlier than year of grant.';
+ }*/
+ }
+ return errors;
+ },
+};
+
+// Works from 1989 and earlier usually display a copyright notice. Did the work have a copyright notice?
+
+TotQuestions.s1q1bi2 = {
+ question:
+ "Published works from 1989 and earlier usually display a copyright notice. Did the work have a copyright notice?",
+ explanation:
+ 'For U.S. works published in certain years, U.S. law required that they feature a "copyright notice" in order to receive federal copyright protection. Whether or not the published version featured a copyright notice can affect the copyright status of these works.',
+ variable: "copyright_notice",
+ input: "radio",
+ values: ["yes", "no", "maybe"],
+};
+
+// Has the work been registered with the United State Copyright Office?
+
+TotQuestions.s1q1c = {
+ question:
+ "Has the work been registered with the United State Copyright Office?",
+ explanation:
+ "Before 1989, registration was one of the ways authors could secure federal copyright in their work. Whether a work was registered can affect copyright status and the timing of termination right.",
+ variable: "work_registered",
+ input: "radio",
+ values: ["yes", "no"], //, "don't know"] GitHub issue #33
+};
+
+// When was the work registered with the United States Copyright Office?
+
+TotQuestions.s1q1ci = {
+ question:
+ "When was the work registered with the United States Copyright Office?",
+ explanation:
+ "Before 1989, registration was one of the ways authors could secure federal copyright in their work. When a work was registered can affect copyright status and the timing of termination right.",
+ variable: "reg_year",
+ input: "year",
+};
+
+// What is the date of the agreement or transfer? ...
+
+TotQuestions.s1q1d = {
+ question: "What is the year of the agreement or transfer?",
+ explanation:
+ "When a transfer took place determines the particular set of termination rules that will be applicable. The timing of a transfer is also needed to know when a work's copyright transfer may be eligible for termination.",
+ variable: "k_year",
+ input: "year",
+ validate: () => {
+ const errors = TotValidation.validDate();
+ if (errors == false) {
+ // Stash the user-entered agreement year
+ TotValues.user_inputted_k_year = parseInt(jQuery(".text-question").val());
+ // If date is before the creation year, use the creation year instead
+ if (TotValues.user_inputted_k_year < TotValues.creation_year) {
+ jQuery(".text-question").val(TotValues.creation_year);
+ }
+ }
+ return errors;
+ },
+ answerDisplayValue: () => {
+ return `Effective: ${TotValues.k_year} User entered: ${TotValues.user_inputted_k_year}`;
+ },
+};
+
+// Did the agreement or transfer include the right of publication?
+
+TotQuestions.s1q1f = {
+ // Last question in section 1, so set this if we've arrived via back button
+ section: 1,
+ question: "Did the agreement or transfer include the right of publication?",
+ explanation:
+ 'If a transfer from 1978 or later includes the right of publication, there is a different set of rules for determining when the transfer is eligible for termination.',
+ variable: "pub_right",
+ input: "radio",
+ values: ["yes", "no", "maybe"],
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Section Two
+////////////////////////////////////////////////////////////////////////////////
+
+// Is the agreement or transfer you want to terminate part of a last will...
+
+TotQuestions.s2q2a = {
+ // First question in section 2
+ section: 2,
+ question:
+ 'Is the agreement or transfer in question part of a last will and testament?',
+ variable: "last_will",
+ input: "radio",
+};
+
+// Are any of the authors still alive?
+
+TotQuestions.s2q2bi = {
+ question:
+ 'Are any of the authors or artists still alive?',
+ explanation:
+ "The copyright term for many works is based on the life of the author.",
+ variable: "any_authors_alive",
+ input: "radio",
+};
+
+// What is the year the last surviving author died?
+
+TotQuestions.s2q2bi2 = {
+ question:
+ 'What is the year the last surviving author or artist died?',
+ explanation:
+ "The copyright term for many works is based on the life of the author.",
+ variable: "death",
+ input: "year",
+};
+
+// Was the work created within the scope of the author’s employment?
+
+TotQuestions.s2q2c = {
+ question:
+ 'Was the work created within the scope of the author’s employment?',
+ variable: "within_scope_of_employment",
+ input: "radio",
+};
+
+// Was there an express agreement between the author and the author's employer to not treat the work as a work made for hire?
+
+TotQuestions.s2q2ci = {
+ question:
+ 'Was there an express agreement the author and the author\'s employer to not treat the work as a work for hire?',
+ variable: "express_agreement",
+ input: "radio",
+};
+
+// Was the work created in response to a special order or commission
+
+TotQuestions.s2q2d = {
+ question:
+ 'Was the work created in response to a special order or commission by some other person or company?',
+ variable: "special_order",
+ input: "radio",
+};
+
+// Was there a signed written agreement regarding the special order...
+
+TotQuestions.s2q2di = {
+ question:
+ 'Was there a signed written agreement regarding the special order or commission which explicitly refers to the work as a work for hire?',
+ variable: "signed_written_agreement",
+ input: "radio",
+};
+
+// Was the work created for use as one of the following? ...
+
+TotQuestions.s2q2dia = {
+ question:
+ 'Was the work created for use as one of the following? —
a contribution to a collective work; a part of a motion picture or other audiovisual work;
a translation;
a supplementary work (such as a foreword, afterword, table, editorial note, musical arrangement, bibliography, appendix, or index);
',
+ variable: "created_as_part_of_motion_picture",
+ input: "radio",
+ values: ["yes", "no", "don't know"],
+};
+
+// Has the original transfer since been renegotiated or altered?
+
+TotQuestions.s2q2e = {
+ question: "Has the original transfer since been renegotiated or altered?",
+ variable: "renego",
+ input: "radio",
+ values: ["yes", "no", "don't know"],
+};
+
+// Did one or more of the authors or artists enter into the agreement...
+
+TotQuestions.s2q2f = {
+ question:
+ 'Did one or more of the authors enter into the agreement or transfer?',
+ variable: "authors_entered_agreement",
+ input: "radio",
+};
+
+// s2q2fii is part of the rule for s2q2f
+
+// Was the agreement or transfer made by a member of...
+
+TotQuestions.s2q2fii = {
+ // Last question in section 2, so set section if we're going back
+ section: 2,
+ question:
+ 'Was the agreement or transfer made by a member of the author\'s immediate family, or by the executors? For more information about which family members qualify, check out the FAQ.',
+ variable: "agreement_by_family_or_executor",
+ input: "radio",
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Storing answers
+////////////////////////////////////////////////////////////////////////////////
+
+TotQuestions.validateAnswer = () => {
+ let result = false;
+ const question = TotQuestions[TotQuestions.current_question];
+ if (question["validate"]) {
+ result = question.validate();
+ } else if (question.type == "year") {
+ result = TotValidation.validDate();
+ } else if (question.type == "text") {
+ // If the text has a minimum length, check it
+ if (jQuery(".text-question").val().length < question.min_chars) {
+ result = `Answer is too short, it must be at least ${question.min_chars} characters`;
+ }
+ }
+ // We don't worry about radio buttons
+ return result;
+};
+
+TotQuestions.getAnswer = () => {
+ const question = TotQuestions[TotQuestions.current_question];
+ let answer = undefined;
+ switch (question?.input) {
+ case "radio":
+ answer = jQuery(':input[type="radio"]:checked').val();
+ break;
+ case "year":
+ if (
+ question.optional != true ||
+ (question.optional == true && jQuery(".text-question").val() != "")
+ ) {
+ answer = parseInt(jQuery(".text-question").val());
+ }
+ break;
+ case "year_or_empty":
+ if (jQuery(".text-question").val() != "") {
+ answer = parseInt(jQuery(".text-question").val());
+ }
+ break;
+ case "text":
+ // Fall through to default
+ default:
+ answer = jQuery(".text-question").val();
+ break;
+ }
+ return answer;
+};
+
+TotQuestions.processAnswer = () => {
+ let result = false;
+ const warnings = TotQuestions.validateAnswer();
+ if (warnings === false) {
+ const question = TotQuestions[TotQuestions.current_question];
+ let answer = TotQuestions.getAnswer();
+ TotValues[question.variable] = answer;
+ // FIXME: handle converting radio buttons to correct store values
+ // while recording their label in the answers table
+ if (answer) {
+ if (typeof question.answerDisplayValue === "function") {
+ answer = question.answerDisplayValue();
+ }
+ TotAnswers.appendAnswer(question.variable, question.question, answer);
+ }
+ TotNotifications.clearAlerts();
+ result = true;
+ } else {
+ TotNotifications.setAlert(warnings);
+ }
+ return result;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Flag and result lookup
+// These messages are stored in a json file so we can also use them in the PDF
+////////////////////////////////////////////////////////////////////////////////
+
+TotQuestions.resultMap = undefined;
+// Asynchronous fetch of data that is accessed synchronously.
+// This data won't be used until after several questions, so this is tolerable.
+
+jQuery
+ .getJSON(
+ jQuery("script[src*='/termination-of-transfer/dist/js/questions.js']")
+ .attr("src")
+ .replace(/dist\/js\/questions\.js.*$/, "") + "assets/js/results.json",
+ )
+ .done((result) => {
+ TotQuestions.resultMap = result;
+ })
+ .fail((jqxhr, textStatus, error) => {
+ const err = textStatus + ", " + error;
+ console.log("Request Failed: " + err);
+ });
+
+TotQuestions.getConclusionDetails = (specifier) => {
+ const path = specifier.split(".");
+ const result = TotQuestions.resultMap["Conclusion"][path[0]][path[1]];
+ return result;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Flow of control
+////////////////////////////////////////////////////////////////////////////////
+
+TotQuestions.first_question = "s1q1a";
+TotQuestions.last_question = "s2q2fii";
+
+TotQuestions.start = () => {
+ jQuery(".questionnaire-section, .question-progress-buttons").removeClass(
+ "hidden",
+ );
+ jQuery(".no-javascript-alert").addClass("hidden");
+ //TotNavigation.disablePrevious();
+ TotRendering.transitionTo(TotQuestions.first_question);
+};
+
+TotQuestions.transitionQuestion = (next_question) => {
+ const previous_question = TotQuestions[TotQuestions.current_question];
+ if (previous_question) {
+ if (previous_question.post) {
+ previous_question.post();
+ }
+ }
+ if (next_question == "finish") {
+ TotQuestions.finish();
+ } else {
+ TotQuestions.current_question = next_question;
+ const question = TotQuestions[TotQuestions.current_question];
+ if (question["pre"]) {
+ question.pre();
+ }
+ TotRendering.transitionTo(question);
+ }
+};
+
+TotQuestions.nextQuestionID = () => {
+ let next_question = TotQuestions.current_question;
+ const rule = TotRules[TotQuestions.current_question];
+ if (typeof rule == "function") {
+ next_question = rule();
+ } else {
+ next_question = rule;
+ }
+ return next_question;
+};
+
+TotQuestions.nextQuestion = () => {
+ // If the answer was OK, move on
+ if (TotQuestions.processAnswer()) {
+ ValuesStack.push();
+ const id = TotQuestions.nextQuestionID();
+ TotValues.question_id = id;
+ if (id == "finish") {
+ TotQuestions.finish();
+ } else {
+ TotQuestions.transitionQuestion(TotValues.question_id);
+ // Scroll down to make sure the input UI is visible
+ jQuery("html,body").animate(
+ {
+ scrollTop: jQuery("#button-question-next").offset().top,
+ },
+ "slow",
+ );
+ }
+ }
+};
+
+TotQuestions.previousQuestion = () => {
+ // If we are going back from *after* the last question, re-enable UI
+ if (TotValues.question_id == "finish") {
+ TotNavigation.unfinishQuestions();
+ }
+ // Don't pop past the very first item
+ if (ValuesStack.height() > 0) {
+ // Go back
+ ValuesStack.pop();
+ TotQuestions.transitionQuestion(TotValues.question_id);
+ TotNotifications.clearAlerts();
+ // Clear previous answer
+ const previous_question = TotQuestions[TotValues.question_id];
+ TotAnswers.removeAnswer(previous_question.variable);
+ // Scroll down to make sure the input UI is visible
+ jQuery("html,body").animate(
+ {
+ scrollTop: jQuery("#button-question-next").offset().top,
+ },
+ "slow",
+ );
+ }
+};
+
+TotQuestions.finish = () => {
+ const obj = TotQuestions.getConclusionDetails(TotValues.conclusion);
+ TotValues.termination_type = obj.title;
+ TotNotifications.setResultAreaMessage(obj, "panel-success");
+ TotNavigation.finishQuestions();
+ if (TotValues.conclusion_generate_pdf) {
+ TotPdf.request();
+ }
+};
+
+TotQuestions.start = () => {
+ TotValues.reset();
+ TotNavigation.showQuestions();
+ TotNavigation.showAnswersTable();
+ TotNavigation.showNextPrevious();
+ jQuery("#button-question-next").on("click", TotQuestions.nextQuestion);
+ jQuery("#button-question-back").on("click", TotQuestions.previousQuestion);
+ // When the user presses "return" in a text area, move to next question
+ jQuery("#question-rendering-area").on("submit", () => {
+ if (jQuery("#button-question-next").is(":enabled")) {
+ jQuery("#button-question-next").click();
+ }
+ return false;
+ });
+ TotQuestions.transitionQuestion(TotQuestions.first_question);
+ TotValues.question_id = TotQuestions.first_question;
+};
+
+jQuery(document).ready(() => {
+ TotQuestions.start();
+});
diff --git a/assets/js/rendering.js b/assets/js/rendering.js
new file mode 100644
index 0000000..eca0a4c
--- /dev/null
+++ b/assets/js/rendering.js
@@ -0,0 +1,168 @@
+/*
+ Termination of Transfer - tool to help in returning authors rights.
+ Copyright (C) 2016 Creative Commons Corporation.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// Rendering UI elements for input
+////////////////////////////////////////////////////////////////////////////////
+
+const TotRendering = {
+ currentSection: 0,
+ sections: [
+ "",
+ "First tell us a few things about the work",
+ "Now, let’s find out whether the work is eligible for termination",
+ "Information about the work",
+ ],
+ questionTemplate: `
+ `,
+ createQuestion: () => {
+ return jQuery(TotRendering.questionTemplate);
+ },
+ common: (config) => {
+ const question = TotRendering.createQuestion();
+ // If this is a question in a different section, change the section header
+ // Section is 1-based, so we can use a simple logical and here.
+ if (config.section && config.section != TotRendering.currentSection) {
+ jQuery("#section-title")
+ .html(TotRendering.sections[config.section])
+ .fadeIn();
+ }
+ question.find(".question-label").html(config.question);
+ if (config.explanation) {
+ question.find(".help-block").html(config.explanation);
+ }
+ question.css("display", "none");
+ // If we're entering this value for the first time (not via the back button)
+ // and this isn't an optional value
+ // don't let the user continue until they enter a value here.
+ if (TotValues[config.variable] === undefined && !config.optional) {
+ TotNavigation.disableNext();
+ } else {
+ TotNavigation.enableNext();
+ }
+ return question;
+ },
+ radio: (config) => {
+ // Multiple choice questions (radio buttons)
+ const question = TotRendering.common(config);
+ const form_group = question.find(".form-group");
+ const name = `input_${config.variable}`;
+ // If we are returning to this via the back button, get the previous value
+ const existing_value = TotValues[config.variable];
+ let radio_button_values = config.values || ["yes", "no"];
+ radio_button_values.forEach((value) => {
+ let radio_button = ``;
+ if (value == existing_value) {
+ radio_button = ``;
+ }
+
+ form_group.append(jQuery(radio_button));
+ });
+ // When the user makes a choice, go straight to the next question
+ form_group.find(':input[type="radio"]').on("click", () => {
+ TotNavigation.enableNext();
+ jQuery("#button-question-next").click();
+ });
+ return question;
+ },
+ makeTextLengthHandler: (element, min_length, optional) => {
+ // text input validator handler
+ return () => {
+ const length = element.val().length;
+ if ((optional && length == 0) || length >= min_length) {
+ TotNavigation.enableNext();
+ } else {
+ TotNavigation.disableNext();
+ }
+ };
+ },
+ text: (config) => {
+ // Text input
+ const question = TotRendering.common(config);
+ const form_group = question.find(".form-group");
+ // const name = "input-" + config.variable;
+ const text_field = jQuery(
+ ``,
+ );
+ form_group.append(text_field);
+ // Set the label
+ // const label = question.find(".question-label").prop("for", name);
+ if (TotValues[config.variable]) {
+ form_group.find("text-question").val(TotValues[config.variable]);
+ }
+ const existing_value = TotValues[config.variable];
+ // Ensure next isn't enabled until enough characters are entered
+ const min_length = config.min_length || 4;
+ const text_field_element = question.find(".text-question");
+ const validator = TotRendering.makeTextLengthHandler(
+ text_field_element,
+ min_length,
+ config.optional,
+ );
+ text_field_element.on("keyup", validator);
+ text_field_element.on("change", validator);
+ // If we are returning to the field and the value has already been set, use it
+ if (existing_value !== undefined) {
+ text_field.val(TotValues[config.variable]);
+ }
+ return question;
+ },
+ year: (config) => {
+ // Year input (text subtype)
+ const question = TotRendering.text(config);
+ const text_field = question.find(".text-question");
+ TotValidation.allowOnlyNumbers(text_field);
+ text_field.prop("maxlength", 4);
+ text_field.prop("placeholder", "1977");
+ return question;
+ },
+ render: (config) => {
+ // Render html UI from config specification
+ let result = undefined;
+ switch (config.input) {
+ case "radio":
+ result = TotRendering.radio(config);
+ break;
+ case "year":
+ result = TotRendering.year(config);
+ break;
+ case "text":
+ // Fall through to default
+ default:
+ result = TotRendering.text(config);
+ break;
+ }
+ return result;
+ },
+ transitionTo: (config) => {
+ const question = TotRendering.render(config);
+ jQuery(".question-form").slideUp("fast", () => {
+ jQuery(this).remove();
+ });
+ jQuery("#question-rendering-area").append(question);
+ question.slideDown("fast");
+ },
+};
diff --git a/wordpress-plugin/js/results.json b/assets/js/results.json
similarity index 100%
rename from wordpress-plugin/js/results.json
rename to assets/js/results.json
diff --git a/assets/js/rules.js b/assets/js/rules.js
new file mode 100644
index 0000000..5f9c241
--- /dev/null
+++ b/assets/js/rules.js
@@ -0,0 +1,524 @@
+/*
+ Termination of Transfer - tool to help in returning authors rights.
+ Copyright (C) 2016 Creative Commons Corporation.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+const TotRules = {};
+
+TotRules.simpleYesNoRule = (variable_id, yesValue, noValue) => {
+ return () => {
+ let result = undefined;
+ if (TotValues[variable_id] == "yes") {
+ result = yesValue;
+ } else {
+ result = noValue;
+ }
+ return result;
+ };
+};
+
+TotRules.jumpToFinish = "finish";
+
+TotRules.conclusion = (conclusion) => {
+ TotValues.conclusion = conclusion;
+ return TotRules.jumpToFinish;
+};
+
+TotRules.conclusionPDF = (conclusion) => {
+ TotRules.conclusion(conclusion);
+ TotValues.conclusion_generate_pdf = true;
+ return TotRules.jumpToFinish;
+};
+
+TotRules.addFlag = (flag) => {
+ TotValues.flags.push(flag);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Calculated/inferred properties
+////////////////////////////////////////////////////////////////////////////////
+
+TotRules.is203 = () => {
+ return TotValues.conclusion == "A.iii";
+};
+
+TotRules.is304 = () => {
+ return ["A.i", "A.ii", "A.i-ii"].indexOf(TotValues.conclusion) > -1;
+};
+
+TotRules.hasPublicDomainFlags = () => {
+ let result = false;
+ for (let i = 0; i < TotValues.flags.length; i++) {
+ if (TotValues.flags[i][0] == "B") {
+ result = true;
+ }
+ }
+ return result;
+};
+
+TotRules.beforeEndOfNoticeWindow = () => {
+ return (
+ (TotValues.notice_end != undefined &&
+ TotValues.notice_end >= TotValues.current_year) ||
+ (TotValues.d_notice_end != undefined &&
+ TotValues.d_notice_end >= TotValues.current_year) ||
+ (TotValues.p_notice_end != undefined &&
+ TotValues.p_notice_end >= TotValues.current_year)
+ );
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Section N Analyses
+////////////////////////////////////////////////////////////////////////////////
+
+TotRules.section304Analysis = () => {
+ // Note that this is part of the logic from the section 203 analysis
+ let result = "s1q1f";
+ if (TotValues.k_year < 1978) {
+ result = "s2q2a";
+ TotRules.addFlag("F.i");
+ if (TotValues.pub_year > 1977 && TotValues.reg_year > 1977) {
+ result = TotRules.conclusion("B.vii");
+ } else {
+ // Under the 1909 Act, copyright term begins at the earlier of
+ // the registration date and the publication date.
+ // If the work is both registered and published use the minimum of them.
+ if (TotValues.reg_year != undefined && TotValues.pub_year != undefined) {
+ TotValues.cright_year = Math.min(
+ TotValues.pub_year,
+ TotValues.reg_year,
+ );
+ }
+ // Otherwise use whichever value is set. One *will* be set here, see top.
+ else {
+ TotValues.cright_year = TotValues.reg_year || TotValues.pub_year;
+ }
+ TotValues.cright_year = Math.min(TotValues.cright_year, 1978);
+ TotValues.term_begin = TotValues.cright_year + 56;
+ TotValues.term_begin = Math.max(TotValues.term_begin, 1978);
+ TotValues.term_end = TotValues.term_begin + 5;
+ TotValues.notice_begin = TotValues.term_begin - 10;
+ TotValues.notice_end = TotValues.term_end - 2;
+ // If the we're presently before the 304(c) window, then we don't have to worry about 304(d)
+ if (TotValues.notice_begin > TotValues.current_year) {
+ TotRules.addFlag("A.i.a");
+ // Following Copyright Office guidance, works copyrighted before 1940 may also be eligible for termination under 304d
+ } else if (TotValues.cright_year < 1940) {
+ TotRules.addFlag("F.ii");
+ TotValues.d_term_begin = TotValues.term_begin + 19;
+ TotValues.d_term_end = TotValues.d_term_begin + 5;
+ TotValues.d_notice_begin = TotValues.d_term_begin - 10;
+ TotValues.d_notice_end = TotValues.d_term_end - 2;
+ if (TotValues.cright_year > 1936) {
+ TotRules.addFlag("G.i");
+ }
+ if (TotValues.cright_year == 1939) {
+ TotRules.addFlag("G.ii.a");
+ }
+ if (TotValues.d_notice_begin > TotValues.current_year) {
+ // time traveler flag -- applies where the present day is between
+ // the 304(c) and 304(d) notice windows
+ TotRules.addFlag("A.iii.a");
+ } else if (TotValues.d_notice_end < TotValues.current_year) {
+ TotRules.addFlag("A.ii.a");
+ }
+ } else if (TotValues.notice_end < TotValues.current_year) {
+ TotRules.addFlag("A.ii.a");
+ } else {
+ // Here for clarity / to reflect decision tree structure
+ // But note that we set it as the result above.
+ result = "s2q2a";
+ }
+ }
+ if (
+ TotValues.d_term_begin != undefined &&
+ TotValues.term_begin != undefined
+ ) {
+ TotRules.addFlag("E.i");
+ }
+ }
+ return result;
+};
+
+TotRules.section203Analysis = () => {
+ let result = "s2q2a";
+ if (typeof TotValues.grant_pub_year !== "undefined") {
+ TotRules.addFlag("F.iv");
+ }
+ TotValues.triggering_pub_year =
+ TotValues.grant_pub_year || TotValues.pub_year;
+ if (TotValues.k_year > 1977) {
+ TotRules.addFlag("F.iii");
+ if (TotValues.pub_right == "yes") {
+ if (TotValues.triggering_pub_year != undefined) {
+ TotValues.term_begin = Math.min(
+ TotValues.triggering_pub_year + 35,
+ TotValues.k_year + 40,
+ );
+ } else {
+ TotValues.term_begin = TotValues.k_year + 40;
+ }
+ } else if (
+ TotValues.triggering_pub_year != TotValues.k_year ||
+ TotValues.pub_right == "no"
+ ) {
+ TotValues.term_begin = TotValues.k_year + 35;
+ }
+ if (TotValues.term_begin != undefined) {
+ TotValues.term_end = TotValues.term_begin + 5;
+ TotValues.notice_begin = TotValues.term_begin - 10;
+ TotValues.notice_end = TotValues.term_end - 2;
+ if (TotValues.notice_begin > TotValues.current_year) {
+ TotRules.addFlag("A.i.a");
+ } else if (TotValues.notice_end < TotValues.current_year) {
+ TotRules.addFlag("A.ii.a");
+ }
+ }
+ if (TotValues.pub_right == "maybe") {
+ TotValues.p_term_begin = TotValues.k_year + 40;
+ if (TotValues.triggering_pub_year != undefined) {
+ TotValues.p_term_begin = Math.min(
+ TotValues.triggering_pub_year + 35,
+ TotValues.p_term_begin,
+ );
+ }
+ TotValues.p_term_end = TotValues.p_term_begin + 5;
+ TotValues.p_notice_begin = TotValues.p_term_begin - 10;
+ TotValues.p_notice_end = TotValues.p_term_end - 2;
+ if (TotValues.p_notice_begin > TotValues.current_year) {
+ TotRules.addFlag("A.i.a");
+ } else if (TotValues.p_notice_end < TotValues.current_year) {
+ TotRules.addFlag("A.ii.a");
+ }
+ }
+ }
+ if (
+ TotValues.p_term_begin != undefined &&
+ TotValues.term_begin != undefined
+ ) {
+ TotRules.addFlag("E.ii");
+ }
+ return result;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Section 1
+////////////////////////////////////////////////////////////////////////////////
+
+// When was the work created?
+
+TotRules.s1q1a = "s1q1b";
+
+// Has the work been published?
+
+TotRules.s1q1b = TotRules.simpleYesNoRule("work_published", "s1q1bi", "s1q1c");
+
+// When was the work first published?
+
+TotRules.s1q1bi = "s1q1bii";
+
+// When was the work first published under the grant?
+// Note that the condition is based on s1q1b, we are inserting this question
+// after 'When was the work first published?' and *then* going on to the
+// questions about registration/notices or not.
+
+TotRules.s1q1bii = () => {
+ let result = undefined;
+ if (TotValues.pub_year < 1923) {
+ result = TotRules.conclusion("B.viii");
+ } else if (TotValues.pub_year < 1990) result = "s1q1bi2";
+ else {
+ result = "s1q1d";
+ }
+ return result;
+};
+
+// Works from 1989 and earlier usually display a copyright notice...
+
+TotRules.s1q1bi2 = () => {
+ let result = undefined;
+ if (TotValues.copyright_notice == "yes") {
+ result = "s1q1c";
+ } else if (TotValues.copyright_notice == "no") {
+ // The same
+ result = "s1q1c";
+ if (TotValues.pub_year < 1989) {
+ TotRules.addFlag("B.i");
+ } else {
+ TotRules.addFlag("B.ii");
+ }
+ } /* maybe */ else {
+ result = "s1q1c";
+ TotRules.addFlag("B.iii");
+ }
+ return result;
+};
+
+// Has the work been registered with the United State Copyright Office?
+
+TotRules.s1q1c = () => {
+ let result = undefined;
+ if (TotValues.work_registered == "yes") {
+ result = "s1q1ci";
+ } else if (TotValues.work_registered == "no") {
+ result = "s1q1d";
+ } /* don't know */ else {
+ // If someone doesn't know, continue without asking for registration number
+ result = "s1q1d";
+ }
+ return result;
+};
+
+// When was the work registered with the United States Copyright Office?
+
+TotRules.s1q1ci = () => {
+ let result = undefined;
+ if (TotValues.reg_year < 1923) {
+ result = TotRules.conclusion("B.viii");
+ } else {
+ result = "s1q1d";
+ }
+ return result;
+};
+
+// For s1q1d,
+// What is the date of the agreement or transfer? ...
+
+TotRules.s1q1d = () => {
+ let result = undefined;
+ if (TotValues.user_inputted_k_year != TotValues.k_year) {
+ TotRules.addFlag("H.i");
+ }
+ if (
+ TotValues.k_year < 1978 &&
+ TotValues.pub_year == undefined &&
+ TotValues.reg_year == undefined
+ ) {
+ result = TotRules.conclusion("B.vii");
+ } else {
+ // Intercept the result so we can add encouragement if things look good
+ result = TotRules.section304Analysis();
+ if (
+ result != TotRules.jumpToFinish &&
+ TotRules.beforeEndOfNoticeWindow() &&
+ !TotRules.hasPublicDomainFlags()
+ ) {
+ TotNotifications.setEncouragement(
+ "Both notice window and copyright status look good, let's get some more details!",
+ );
+ }
+ }
+ return result;
+};
+
+// Did the agreement or transfer include the right of publication?
+
+TotRules.s1q1f = () => {
+ // Intercept the result so we can add encouragement if things look good
+ let result = TotRules.section203Analysis();
+ if (
+ result != TotRules.jumpToFinish &&
+ TotRules.beforeEndOfNoticeWindow() &&
+ !TotRules.hasPublicDomainFlags()
+ ) {
+ TotNotifications.setEncouragement(
+ "Both notice window and copyright status look good, let's get some more details!",
+ );
+ }
+ return result;
+};
+
+TotRules.section203Analysis;
+
+////////////////////////////////////////////////////////////////////////////////
+// Section 2
+////////////////////////////////////////////////////////////////////////////////
+
+// Is the agreement or transfer you want to terminate part of a last will...
+
+TotRules.s2q2a = () => {
+ let result = undefined;
+ if (TotValues.last_will == "yes") {
+ result = TotRules.conclusion("B.iv");
+ } else {
+ if (
+ TotValues.creation_year > 1977 ||
+ ((TotValues.pub_year == undefined || TotValues.pub_year > 1977) &&
+ (TotValues.reg_year == undefined || TotValues.reg_year > 1977))
+ ) {
+ result = "s2q2bi";
+ } else {
+ result = "s2q2c";
+ }
+ }
+ return result;
+};
+
+// Are any of the authors still alive?
+// It's i) because the conditional logic that starts b is included in a
+
+TotRules.s2q2bi = () => {
+ let result = undefined;
+ if (TotValues.any_authors_alive == "yes") {
+ result = "s2q2c";
+ } else {
+ result = "s2q2bi2";
+ }
+ return result;
+};
+
+// What is the year the last surviving author died?
+
+TotRules.s2q2bi2 = () => {
+ let result = undefined;
+ // creation_year is always set, pub_year may not be, death will be here
+ if (TotValues.creation_year > 1977) {
+ TotValues.pd = TotValues.death + 71;
+ } else if (TotValues.pub_year != undefined && TotValues.pub_year < 2003) {
+ TotValues.pd = Math.max(TotValues.death + 71, 2048);
+ } else {
+ TotValues.pd = Math.max(TotValues.death + 71, 2003);
+ }
+ // pd *will* have been set in the if/else block
+ if (TotValues.current_year > TotValues.pd) {
+ result = TotRules.conclusion("B.viii");
+ } else {
+ result = "s2q2c";
+ }
+ return result;
+};
+
+// Was the work created within the scope of the author’s employment?
+
+TotRules.s2q2c = () => {
+ let result = undefined;
+ if (TotValues.within_scope_of_employment == "yes") {
+ if (TotValues.creation_year > 1977) {
+ result = "s2q2ci";
+ } else {
+ result = TotRules.conclusion("B.i");
+ }
+ } else {
+ result = "s2q2d";
+ }
+ return result;
+};
+
+// Was there an express agreement between you...
+
+TotRules.s2q2ci = () => {
+ let result = undefined;
+ if (TotValues.express_agreement == "yes") {
+ result = "s2q2d";
+ } else {
+ result = TotRules.conclusion("B.i");
+ }
+ return result;
+};
+
+// Was the work created in response to a special order or commission?
+
+TotRules.s2q2d = () => {
+ let result = undefined;
+ if (TotValues.special_order == "yes") {
+ if (TotValues.creation_year < 1978) {
+ TotRules.addFlag("D.i");
+ result = "s2q2e";
+ } else {
+ result = "s2q2di";
+ }
+ } else {
+ result = "s2q2e";
+ }
+ return result;
+};
+
+// Was there a signed written agreement regarding the special order...
+
+TotRules.s2q2di = () => {
+ let result = undefined;
+ if (TotValues.signed_written_agreement == "yes") {
+ if (TotValues.creation_year < 1978) {
+ result = TotRules.conclusion("B.iii");
+ } else {
+ result = "s2q2dia";
+ }
+ } else {
+ result = "s2q2e";
+ }
+ return result;
+};
+
+// Was the work created for use as one of the following? ...
+
+TotRules.s2q2dia = () => {
+ let result = undefined;
+ if (TotValues.created_as_part_of_motion_picture == "yes") {
+ result = TotRules.conclusion("C.ii");
+ } else if (TotValues.created_as_part_of_motion_picture == "no") {
+ result = "s2q2e";
+ } /* don't know */ else {
+ TotRules.addFlag("D.ii");
+ result = "s2q2e";
+ }
+ return result;
+};
+
+// Has the original transfer since been renegotiated or altered?
+
+TotRules.s2q2e = () => {
+ let result = "s2q2f";
+ if (TotValues.renego == "yes") {
+ TotRules.addFlag("C.i");
+ } else if (TotValues.renego == "no") {
+ // Continue
+ } /* don't know */ else {
+ TotRules.addFlag("C.ii");
+ }
+ return result;
+};
+
+// Did one or more of the authors or artists enter into the agreement...
+
+TotRules.s2q2f = () => {
+ let result = undefined;
+ if (TotValues.authors_entered_agreement == "yes") {
+ if (TotValues.k_year < 1978) {
+ result = TotRules.conclusionPDF("A.i-ii");
+ } /*if (k_year > 1977)*/ else {
+ result = TotRules.conclusionPDF("A.iii");
+ }
+ } else {
+ if (TotValues.k_year < 1978) {
+ result = "s2q2fii";
+ } /*if (TotValues.k_year > 1977)*/ else {
+ result = TotRules.conclusion("B.vi");
+ }
+ }
+ return result;
+};
+
+// Was the agreement or transfer made by a member of...
+
+TotRules.s2q2fii = () => {
+ let result = undefined;
+ if (TotValues.agreement_by_family_or_executor) {
+ result = TotRules.conclusionPDF("A.i-ii");
+ } else {
+ result = TotRules.conclusion("B.v");
+ }
+ return result;
+};
diff --git a/assets/js/validation.js b/assets/js/validation.js
new file mode 100644
index 0000000..bf9a656
--- /dev/null
+++ b/assets/js/validation.js
@@ -0,0 +1,72 @@
+/*
+ Termination of Transfer - tool to help in returning authors rights.
+ Copyright (C) 2016 Creative Commons Corporation.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// TotValidation of values and of UI state
+////////////////////////////////////////////////////////////////////////////////
+
+const TotValidation = {};
+
+// Naughty. If we're going to monkeypatch we should have a file for these
+
+String.prototype.capitalizeFirstLetter = () => {
+ return this.charAt(0).toUpperCase() + this.slice(1);
+};
+
+TotValidation.allowOnlyNumbers = (element) => {
+ // http://stackoverflow.com/a/995193
+ element.keydown((e) => {
+ // Allow: backspace, delete, tab, escape, enter and .
+ if (
+ jQuery.inArray(e.keyCode, [46, 8, 9, 27, 13, 110, 190]) !== -1 ||
+ // Allow: Ctrl+A, Command+A
+ (e.keyCode == 65 && (e.ctrlKey === true || e.metaKey === true)) ||
+ // Allow: home, end, left, right, down, up
+ (e.keyCode >= 35 && e.keyCode <= 40)
+ ) {
+ // let it happen, don't do anything
+ return;
+ }
+ // Ensure that it is a number and stop the keypress
+ if (
+ (e.shiftKey || e.keyCode < 48 || e.keyCode > 57) &&
+ (e.keyCode < 96 || e.keyCode > 105)
+ ) {
+ e.preventDefault();
+ }
+ });
+};
+
+// false here means no errors, a string means errors
+
+TotValidation.validDate = () => {
+ const text_field = jQuery(".text-question");
+ const date = text_field.val();
+ let result = false;
+ const errors = [];
+ if (!date.match(/[0-9]{4}/)) {
+ errors.push("date must be four digits");
+ }
+ if (parseInt(date) > TotValues.current_year) {
+ errors.push("date must be in the past");
+ }
+ if (errors.length != 0) {
+ result = `${errors.join().capitalizeFirstLetter()}.`;
+ }
+ return result;
+};
diff --git a/assets/js/values.js b/assets/js/values.js
new file mode 100644
index 0000000..5f75684
--- /dev/null
+++ b/assets/js/values.js
@@ -0,0 +1,74 @@
+/*
+ Termination of Transfer - tool to help in returning authors rights.
+ Copyright (C) 2016 Creative Commons Corporation.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// Storing answers and computed values
+// Questions save their answers here,
+// Rules consult these values and add their own.
+////////////////////////////////////////////////////////////////////////////////
+
+let TotValues = {};
+
+TotValues.reset = () => {
+ const now = new Date();
+ TotValues = {
+ current_date: now,
+ current_year: now.getFullYear(),
+ flags: [],
+ };
+};
+
+//FIXME: Hello namespace pollution
+
+const totVarsToTitles = {
+ work_authors: "Author",
+ work_title: "Title of Work",
+ creation_year: "Creation Year",
+ pub_year: "Publication Year",
+ grant_pub_year: "Publication Year Under Grant",
+ triggering_pub_year: "Triggering Publication Date",
+ k_year: "Effective Grant Year",
+ user_inputted_k_year: "User Entered Grant Year",
+ reg_year: "Copyright Registration Year",
+ work_copyright_reg_num: "Registration Number",
+ termination_type: "Termination Type",
+ work_agreement_type: "Agreement or Transfer Type",
+ work_agreement_desc: "Agreement or Transfer Description",
+ //'': 'Grantor',
+};
+
+let ValuesStack = {};
+
+ValuesStack._stack = [];
+
+ValuesStack.height = () => {
+ return ValuesStack._stack.length;
+};
+
+ValuesStack.push = () => {
+ // Handle the date not liking being serialized.
+ const now = TotValues.current_date;
+ ValuesStack._stack.push(TotValues);
+ // Deep clone
+ TotValues = JSON.parse(JSON.stringify(TotValues));
+ TotValues.current_date = now;
+};
+
+ValuesStack.pop = () => {
+ TotValues = ValuesStack._stack.pop();
+};
diff --git a/assets/js/widgets.js b/assets/js/widgets.js
new file mode 100644
index 0000000..584e9bb
--- /dev/null
+++ b/assets/js/widgets.js
@@ -0,0 +1,161 @@
+/*
+ Termination of Transfer - tool to help in returning authors rights.
+ Copyright (C) 2016 Creative Commons Corporation.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// Control of the html UI
+////////////////////////////////////////////////////////////////////////////////
+
+//var Widgets = {};
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual display of the user's responses
+////////////////////////////////////////////////////////////////////////////////
+
+const TotAnswers = {};
+
+TotAnswers.resetAnswers = () => {
+ jQuery("#answers-table-rows").empty();
+};
+
+TotAnswers.appendAnswer = (myId, label, value) => {
+ if (!label) {
+ label = jQuery(`#${myId}`).parent().find("label").first().text();
+ }
+ // If the user has gone back and is changing the answer, first remove it
+ TotAnswers.removeAnswer(myId);
+ jQuery("#answers-table-rows").append(
+ `
As you respond to the questions we\'ll save the answers here.
',
+ );
+};
+
+TotNotifications.removeAnswersHint = () => {
+ jQuery("#answers-table-row-placeholder").remove();
+};
+
+TotNotifications.displayResultArea = () => {
+ jQuery("#result-area").removeClass("hidden");
+};
+
+TotNotifications.hideResultArea = () => {
+ jQuery("#result-area").addClass("hidden");
+};
+
+TotNotifications.setResultAreaMessage = (obj, panelClass) => {
+ jQuery("#result-area").addClass(panelClass);
+ jQuery("#result-area-title").html(obj.title);
+ jQuery("#result-area-message").html(obj.description);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Navigation of questions
+////////////////////////////////////////////////////////////////////////////////
+
+const TotNavigation = {};
+
+let progressStack = [];
+
+// These return true so we can use them as "handlers" in simpleNextQuestion
+
+TotNavigation.disableNext = () => {
+ jQuery("#button-question-next").prop("disabled", true);
+ return true;
+};
+
+TotNavigation.disablePrevious = () => {
+ jQuery("#button-question-back").prop("disabled", true);
+ return true;
+};
+
+TotNavigation.enableNext = () => {
+ jQuery("#button-question-next").prop("disabled", false);
+ return true;
+};
+
+TotNavigation.enablePrevious = () => {
+ jQuery("#button-question-back").prop("disabled", false);
+ return true;
+};
+
+TotNavigation.showNextPrevious = () => {
+ jQuery("#question-progress-buttons").removeClass("hidden");
+};
+
+TotNavigation.hideQuestions = () => {
+ jQuery("#questionnaire-section").addClass("hidden");
+ jQuery(".form-group").addClass("hidden");
+};
+
+TotNavigation.showQuestions = () => {
+ jQuery("#questionnaire-section").removeClass("hidden");
+ jQuery(".form-group").removeClass("hidden");
+};
+
+TotNavigation.hideNoJSWarning = () => {};
+
+TotNavigation.showAnswersTable = () => {
+ jQuery("#answers-table").removeClass("hidden");
+};
+
+// After this, do not restart the questionnaire, reload the page to restart
+
+TotNavigation.finishQuestions = () => {
+ TotNavigation.hideQuestions();
+ TotNotifications.displayResultArea();
+ TotNavigation.disableNext();
+ jQuery("#button-restart").removeClass("hidden");
+};
+
+TotNavigation.unfinishQuestions = () => {
+ TotNavigation.showQuestions();
+ TotNotifications.hideResultArea();
+ jQuery("#button-restart").addClass("hidden");
+};
diff --git a/babel.config.json b/babel.config.json
new file mode 100644
index 0000000..69fe715
--- /dev/null
+++ b/babel.config.json
@@ -0,0 +1,3 @@
+{
+ "presets": ["@babel/preset-env"]
+}
diff --git a/composer.json b/composer.json
index 646346c..99c9f51 100644
--- a/composer.json
+++ b/composer.json
@@ -1,8 +1,11 @@
{
"name": "creativecommons/termination-of-transfer",
- "require": {
- "mpdf/mpdf": "^6.0",
- "smarty/smarty": "^3.1"
+ "type": "wordpress-plugin",
+ "description": "Termination of Transfer tool",
+ "keywords": ["WordPress", "plugins", "termination", "contract", "creativecommons", "php"],
+ "support": {
+ "issues": "https://github.com/creativecommons/termination-of-transfer/issues?state=open",
+ "source": "https://github.com/creativecommons/termination-of-transfer"
},
"license": "GNU AGPL v3+",
"authors": [
@@ -10,5 +13,27 @@
"name": "Rob Myers",
"email": "rob@robmyers.org"
}
+ ],
+ "minimum-stability": "dev",
+ "prefer-stable": true,
+ "require": {
+ "php": ">=7.4",
+ "mpdf/mpdf": "^6.0",
+ "smarty/smarty": "^3.1"
+ },
+ "config": {
+ "process-timeout": 1800,
+ "fxp-asset": {
+ "enabled": false
+ }
+ },
+ "autoload": {
+ "psr-4": {"CreativeCommons_TOT\\": "./src"}
+ },
+ "repositories": [
+ {
+ "type": "composer",
+ "url": "https://asset-packagist.org"
+ }
]
}
diff --git a/composer.lock b/composer.lock
index 2bb6956..fc89c42 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "be9b858b5d4ad979b3d96414485baac0",
+ "content-hash": "c7b180543aade87b3b7942f30dc807f7",
"packages": [
{
"name": "mpdf/mpdf",
- "version": "v6.1.1",
+ "version": "v6.1.3",
"source": {
"type": "git",
"url": "https://github.com/mpdf/mpdf.git",
- "reference": "9116f8b28e86d1eaf858d1a4623d26a910441672"
+ "reference": "7f138bf7508eac895ac2c13d2509b056ac7e7e97"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/mpdf/mpdf/zipball/9116f8b28e86d1eaf858d1a4623d26a910441672",
- "reference": "9116f8b28e86d1eaf858d1a4623d26a910441672",
+ "url": "https://api.github.com/repos/mpdf/mpdf/zipball/7f138bf7508eac895ac2c13d2509b056ac7e7e97",
+ "reference": "7f138bf7508eac895ac2c13d2509b056ac7e7e97",
"shasum": ""
},
"require": {
@@ -55,20 +55,25 @@
"php",
"utf-8"
],
- "time": "2016-04-28T18:19:01+00:00"
+ "support": {
+ "docs": "http://mpdf.github.io",
+ "issues": "https://github.com/mpdf/mpdf/issues",
+ "source": "https://github.com/mpdf/mpdf"
+ },
+ "time": "2016-12-12T10:42:18+00:00"
},
{
"name": "setasign/fpdi",
- "version": "1.6.1",
+ "version": "1.6.2",
"source": {
"type": "git",
"url": "https://github.com/Setasign/FPDI.git",
- "reference": "5b899b2b41463bf261aa69840fd30b50950a500c"
+ "reference": "a6ad58897a6d97cc2d2cd2adaeda343b25a368ea"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Setasign/FPDI/zipball/5b899b2b41463bf261aa69840fd30b50950a500c",
- "reference": "5b899b2b41463bf261aa69840fd30b50950a500c",
+ "url": "https://api.github.com/repos/Setasign/FPDI/zipball/a6ad58897a6d97cc2d2cd2adaeda343b25a368ea",
+ "reference": "a6ad58897a6d97cc2d2cd2adaeda343b25a368ea",
"shasum": ""
},
"suggest": {
@@ -104,24 +109,28 @@
"fpdi",
"pdf"
],
- "time": "2015-11-30T10:53:14+00:00"
+ "support": {
+ "issues": "https://github.com/Setasign/FPDI/issues",
+ "source": "https://github.com/Setasign/FPDI/tree/master"
+ },
+ "time": "2017-05-11T14:25:49+00:00"
},
{
"name": "smarty/smarty",
- "version": "v3.1.39",
+ "version": "v3.1.47",
"source": {
"type": "git",
"url": "https://github.com/smarty-php/smarty.git",
- "reference": "e27da524f7bcd7361e3ea5cdfa99c4378a7b5419"
+ "reference": "a09364fe1706cb465e910eb040e592053d7effb8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/smarty-php/smarty/zipball/e27da524f7bcd7361e3ea5cdfa99c4378a7b5419",
- "reference": "e27da524f7bcd7361e3ea5cdfa99c4378a7b5419",
+ "url": "https://api.github.com/repos/smarty-php/smarty/zipball/a09364fe1706cb465e910eb040e592053d7effb8",
+ "reference": "a09364fe1706cb465e910eb040e592053d7effb8",
"shasum": ""
},
"require": {
- "php": ">=5.2"
+ "php": "^5.2 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^7.5 || ^6.5 || ^5.7 || ^4.8",
@@ -165,18 +174,20 @@
"forum": "http://www.smarty.net/forums/",
"irc": "irc://irc.freenode.org/smarty",
"issues": "https://github.com/smarty-php/smarty/issues",
- "source": "https://github.com/smarty-php/smarty/tree/v3.1.39"
+ "source": "https://github.com/smarty-php/smarty/tree/v3.1.47"
},
- "time": "2021-02-17T21:57:51+00:00"
+ "time": "2022-09-14T11:29:00+00:00"
}
],
"packages-dev": [],
"aliases": [],
- "minimum-stability": "stable",
+ "minimum-stability": "dev",
"stability-flags": [],
- "prefer-stable": false,
+ "prefer-stable": true,
"prefer-lowest": false,
- "platform": [],
+ "platform": {
+ "php": ">=7.4"
+ },
"platform-dev": [],
- "plugin-api-version": "2.0.0"
+ "plugin-api-version": "2.3.0"
}
diff --git a/dev/docker-compose.yml b/dev/docker-compose.yml
new file mode 100644
index 0000000..ea2ec14
--- /dev/null
+++ b/dev/docker-compose.yml
@@ -0,0 +1,50 @@
+version: '3.2'
+
+services:
+ wp:
+ build:
+ context: ../
+ restart: always
+ environment:
+ WORDPRESS_DEBUG: 1
+ WORDPRESS_DB_HOST: db
+ WORDPRESS_DB_NAME: wordpress
+ WORDPRESS_DB_PASSWORD: dbPassword
+ WORDPRESS_DB_USER: dbUsername
+ ports:
+ - 8701:80
+ links:
+ - db:mysql
+ volumes:
+ - .././:/var/www/html/wp-content/plugins/termination-of-transfer
+ depends_on:
+ - db
+
+ db:
+ container_name: 'tot-mariadb'
+ hostname: db
+ image: mariadb
+ restart: always
+ environment:
+ MARIADB_ROOT_PASSWORD: rootPassword
+ MARIADB_USER: dbUsername
+ MARIADB_PASSWORD: dbPassword
+ volumes:
+ - sql:/var/lib/mysql
+ - ./my.cnf:/etc/mysql/my.cnf
+ #entrypoint: mysqld_safe --skip-grant-tables --user=mysql
+
+ dbsetup:
+ image: mariadb
+ restart: "no"
+ links:
+ - db:mysql
+ depends_on:
+ - db
+ volumes:
+ - sql:/var/lib/mysql
+ - ./my.cnf:/etc/mysql/my.cnf
+ entrypoint: [ "bash", "-c", "sleep 10 && mysql -h \"db\" -Be \"CREATE DATABASE IF NOT EXISTS wordpress; GRANT ALL PRIVILEGES ON \"wordpress\".* TO \"dbUsername\"@'%' WITH GRANT OPTION;\""]
+
+volumes:
+ sql:
diff --git a/dev/my.cnf b/dev/my.cnf
new file mode 100644
index 0000000..9d9f4cd
--- /dev/null
+++ b/dev/my.cnf
@@ -0,0 +1,139 @@
+#
+# These groups are read by MariaDB server.
+# Use it for options that only the server (but not clients) should see
+#
+# See the examples of server my.cnf files in /usr/share/mysql/
+#
+
+# this is read by the standalone daemon and embedded servers
+[server]
+
+# this is only for the mysqld standalone daemon
+[mysqld]
+
+#
+# * Basic Settings
+#
+user = mysql
+pid-file = /var/run/mysqld/mysqld.pid
+socket = /var/run/mysqld/mysqld.sock
+port = 3306
+basedir = /usr
+datadir = /var/lib/mysql
+tmpdir = /tmp
+lc-messages-dir = /usr/share/mysql
+skip-external-locking
+
+# Instead of skip-networking the default is now to listen only on
+# localhost which is more compatible and is not less secure.
+bind-address = 0.0.0.0
+
+#
+# * Fine Tuning
+#
+key_buffer_size = 16M
+max_allowed_packet = 16M
+thread_stack = 192K
+thread_cache_size = 8
+# This replaces the startup script and checks MyISAM tables if needed
+# the first time they are touched
+myisam_recover_options = BACKUP
+#max_connections = 100
+#table_cache = 64
+#thread_concurrency = 10
+
+#
+# * Query Cache Configuration
+#
+query_cache_limit = 1M
+query_cache_size = 16M
+
+#
+# * Logging and Replication
+#
+# Both location gets rotated by the cronjob.
+# Be aware that this log type is a performance killer.
+# As of 5.1 you can enable the log at runtime!
+#general_log_file = /var/log/mysql/mysql.log
+#general_log = 1
+#
+# Error log - should be very few entries.
+#
+log_error = /var/log/mysql/error.log
+#
+# Enable the slow query log to see queries with especially long duration
+#slow_query_log_file = /var/log/mysql/mariadb-slow.log
+#long_query_time = 10
+#log_slow_rate_limit = 1000
+#log_slow_verbosity = query_plan
+#log-queries-not-using-indexes
+#
+# The following can be used as easy to replay backup logs or for replication.
+# note: if you are setting up a replication slave, see README.Debian about
+# other settings you may need to change.
+#server-id = 1
+#log_bin = /var/log/mysql/mysql-bin.log
+expire_logs_days = 10
+max_binlog_size = 100M
+#binlog_do_db = include_database_name
+#binlog_ignore_db = exclude_database_name
+
+#
+# * InnoDB
+#
+# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
+# Read the manual for more InnoDB related options. There are many!
+
+#
+# * Security Features
+#
+# Read the manual, too, if you want chroot!
+# chroot = /var/lib/mysql/
+#
+# For generating SSL certificates you can use for example the GUI tool "tinyca".
+#
+# ssl-ca=/etc/mysql/cacert.pem
+# ssl-cert=/etc/mysql/server-cert.pem
+# ssl-key=/etc/mysql/server-key.pem
+#
+# Accept only connections using the latest and most secure TLS protocol version.
+# ..when MariaDB is compiled with OpenSSL:
+# ssl-cipher=TLSv1.2
+# ..when MariaDB is compiled with YaSSL (default in Debian):
+# ssl=on
+
+#
+# * Character sets
+#
+# MySQL/MariaDB default is Latin1, but in Debian we rather default to the full
+# utf8 4-byte character set. See also client.cnf
+#
+character-set-server = utf8mb4
+collation-server = utf8mb4_general_ci
+
+#
+# * Unix socket authentication plugin is built-in since 10.0.22-6
+#
+# Needed so the root database user can authenticate without a password but
+# only when running as the unix root user.
+#
+# Also available for other users if required.
+# See https://mariadb.com/kb/en/unix_socket-authentication-plugin/
+
+# this is only for embedded server
+[embedded]
+
+# This group is only read by MariaDB servers, not by MySQL.
+# If you use the same .cnf file for MySQL and MariaDB,
+# you can put MariaDB-only options here
+[mariadb]
+
+# This group is only read by MariaDB-10.1 servers.
+# If you use the same .cnf file for MariaDB of different versions,
+# use this group for options that older servers don't understand
+[mariadb-10.1]
+
+#client login details
+[client]
+user = root
+password = rootPassword
diff --git a/dist/js/pdf.js b/dist/js/pdf.js
new file mode 100644
index 0000000..cb2c8d8
--- /dev/null
+++ b/dist/js/pdf.js
@@ -0,0 +1,102 @@
+"use strict";
+
+/*
+ Termination of Transfer - tool to help in returning authors rights.
+ Copyright (C) 2016 Creative Commons Corporation.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// PDF Generation
+// (browser-side data preparation and call to server)
+////////////////////////////////////////////////////////////////////////////////
+
+var TotPdf = {};
+TotPdf.url = "".concat(jQuery("script[src*='/termination-of-transfer/dist/js/pdf.js']").attr("src").replace(/dist\/js\/pdf\.js.*$/, ""), "pdf-result.php");
+TotPdf.appendProperty = function (details, key, value) {
+ var mapping = {
+ key: key,
+ value: value
+ };
+ details.push(mapping);
+};
+TotPdf.append203Windows = function (details) {
+ var notice = "";
+ var termination = "";
+ if (TotValues.notice_begin != undefined) {
+ notice += "".concat(TotValues.notice_begin, "-").concat(TotValues.notice_end);
+ termination += "".concat(TotValues.term_begin, "-").concat(TotValues.term_end);
+ }
+ if (TotValues.p_term_begin != undefined) {
+ if (notice != "") {
+ notice += " or ";
+ termination += " or ";
+ }
+ notice += "".concat(TotValues.p_notice_begin, "-").concat(TotValues.p_notice_end);
+ termination += "".concat(TotValues.p_term_begin, "-").concat(TotValues.p_term_end);
+ }
+ TotPdf.appendProperty(details, '§ 203 notice window', notice);
+ TotPdf.appendProperty(details, '§ 203 termination window', termination);
+};
+TotPdf.append304Windows = function (details) {
+ TotPdf.appendProperty(details, '§ 304(c) notice window begins', TotValues.notice_begin);
+ TotPdf.appendProperty(details, '§ 304(c) notice window ends', TotValues.notice_end);
+ TotPdf.appendProperty(details, '§ 304(c) termination window begins', TotValues.term_begin);
+ TotPdf.appendProperty(details, '§ 304(c) termination window ends', TotValues.term_end);
+ if (TotValues.d_notice_begin != undefined) {
+ TotPdf.appendProperty(details, '§ 304(d) notice window begins', TotValues.d_notice_begin);
+ TotPdf.appendProperty(details, '§ 304(d) notice window ends', TotValues.d_notice_end);
+ TotPdf.appendProperty(details, '§ 304(d) termination window begins', TotValues.d_term_begin);
+ TotPdf.appendProperty(details, '§ 304(d) termination window ends', TotValues.d_term_end);
+ }
+};
+TotPdf.appendWindows = function (details) {
+ if (TotRules.is203()) {
+ TotPdf.append203Windows(details);
+ } else if (TotRules.is304()) {
+ TotPdf.append304Windows(details);
+ }
+};
+TotPdf.details = function () {
+ var details = [];
+ Object.getOwnPropertyNames(totVarsToTitles).forEach(function (key) {
+ if (TotValues[key] != undefined && TotValues[key] != "") {
+ TotPdf.appendProperty(details, totVarsToTitles[key], TotValues[key]);
+ }
+ });
+ TotPdf.appendWindows(details);
+ return details;
+};
+TotPdf.request = function () {
+ var data = {
+ report_timestamp: TotValues.current_date.getTime() / 1000,
+ flags: TotValues.flags.sort(),
+ // Sorts inline & returns, so OK here
+ conclusion: TotValues.conclusion,
+ details: TotPdf.details()
+ };
+ var totform = document.createElement("FORM");
+ totform.setAttribute("action", TotPdf.url);
+ totform.setAttribute("method", "post");
+ totform.setAttribute("enctype", "multipart/form-data");
+ totform.setAttribute("target", "_blank");
+ var data_field = document.createElement("INPUT");
+ data_field.setAttribute("type", "hidden");
+ data_field.setAttribute("name", "data");
+ data_field.setAttribute("value", JSON.stringify(data));
+ totform.appendChild(data_field);
+ jQuery("body").append(totform);
+ totform.submit();
+};
diff --git a/dist/js/questions.js b/dist/js/questions.js
new file mode 100644
index 0000000..4ee3072
--- /dev/null
+++ b/dist/js/questions.js
@@ -0,0 +1,459 @@
+"use strict";
+
+/*
+ Termination of Transfer - tool to help in returning authors rights.
+ Copyright (C) 2016 Creative Commons Corporation.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// Presentation of questions, and main flow of control
+// (This is slightly overloaded)
+////////////////////////////////////////////////////////////////////////////////
+
+var TotQuestions = {};
+
+////////////////////////////////////////////////////////////////////////////////
+// Section One
+////////////////////////////////////////////////////////////////////////////////
+
+// When was the work created?
+
+TotQuestions.s1q1a = {
+ section: 1,
+ question: "When was the work created?",
+ explanation: "The year in which a work was created can affect its copyright status and its treatment under U.S. copyright law. Most importantly, the tool is concerned with whether a worked was made before or after January 1, 1978, when the most recent overhaul of U.S. copyright went into effect.",
+ variable: "creation_year",
+ input: "year",
+ pre: function pre() {
+ TotNavigation.disablePrevious();
+ TotNotifications.displayAnswersHint();
+ },
+ post: function post() {
+ TotNotifications.removeAnswersHint();
+ }
+};
+
+// Has the work been published?
+
+TotQuestions.s1q1b = {
+ question: "Has the work been published?",
+ explanation: 'Whether a work has been published can affect its copyright status and factor into the timing of a termination right. Note that "publication" has a particular meaning in U.S. copyright law, as discussed in our glossary.',
+ variable: "work_published",
+ input: "radio",
+ pre: function pre() {
+ TotNavigation.enablePrevious();
+ }
+};
+
+// When was the work first published?
+
+TotQuestions.s1q1bi = {
+ variable: "pub_year",
+ question: "When was the work first published?",
+ explanation: 'When a work was published can affect its copyright status and factor into the timing of a termination right. Note that "publication" has a particular meaning in U.S. copyright law, as discussed in our glossary.',
+ input: "year",
+ validate: function validate() {
+ return TotValidation.validDate() || (parseInt(jQuery(".text-question").val()) < TotValues.creation_year ? "The publication year cannot be earlier than the creation year." : false);
+ }
+};
+
+// When was the work first published under the grant?
+
+TotQuestions.s1q1bii = {
+ section: 1,
+ question: "When was the work first published under the grant?",
+ explanation: 'When a work was first published under the grant (which may be different than the the date the work was published for the first time) can factor into the timing of a termination right. Note that "publication" has a particular meaning in U.S. copyright law, as discussed in our glossary.',
+ variable: "grant_pub_year",
+ input: "year",
+ validate: function validate() {
+ var errors = TotValidation.validDate();
+ if (errors == false) {
+ var year = parseInt(jQuery(".text-question").val());
+ if (year < TotValues.creation_year) {
+ errors = "Year of publication under grant cannot be earlier than year of creation.";
+ } else if (year < TotValues.pub_year) {
+ errors = "Year of publication under grant cannot be earlier than year of initial publication.";
+ } /* else if (year < TotValues.k_year) {
+ errors = 'Year of publication under grant cannot be earlier than year of grant.';
+ }*/
+ }
+
+ return errors;
+ }
+};
+
+// Works from 1989 and earlier usually display a copyright notice. Did the work have a copyright notice?
+
+TotQuestions.s1q1bi2 = {
+ question: "Published works from 1989 and earlier usually display a copyright notice. Did the work have a copyright notice?",
+ explanation: 'For U.S. works published in certain years, U.S. law required that they feature a "copyright notice" in order to receive federal copyright protection. Whether or not the published version featured a copyright notice can affect the copyright status of these works.',
+ variable: "copyright_notice",
+ input: "radio",
+ values: ["yes", "no", "maybe"]
+};
+
+// Has the work been registered with the United State Copyright Office?
+
+TotQuestions.s1q1c = {
+ question: "Has the work been registered with the United State Copyright Office?",
+ explanation: "Before 1989, registration was one of the ways authors could secure federal copyright in their work. Whether a work was registered can affect copyright status and the timing of termination right.",
+ variable: "work_registered",
+ input: "radio",
+ values: ["yes", "no"] //, "don't know"] GitHub issue #33
+};
+
+// When was the work registered with the United States Copyright Office?
+
+TotQuestions.s1q1ci = {
+ question: "When was the work registered with the United States Copyright Office?",
+ explanation: "Before 1989, registration was one of the ways authors could secure federal copyright in their work. When a work was registered can affect copyright status and the timing of termination right.",
+ variable: "reg_year",
+ input: "year"
+};
+
+// What is the date of the agreement or transfer? ...
+
+TotQuestions.s1q1d = {
+ question: "What is the year of the agreement or transfer?",
+ explanation: "When a transfer took place determines the particular set of termination rules that will be applicable. The timing of a transfer is also needed to know when a work's copyright transfer may be eligible for termination.",
+ variable: "k_year",
+ input: "year",
+ validate: function validate() {
+ var errors = TotValidation.validDate();
+ if (errors == false) {
+ // Stash the user-entered agreement year
+ TotValues.user_inputted_k_year = parseInt(jQuery(".text-question").val());
+ // If date is before the creation year, use the creation year instead
+ if (TotValues.user_inputted_k_year < TotValues.creation_year) {
+ jQuery(".text-question").val(TotValues.creation_year);
+ }
+ }
+ return errors;
+ },
+ answerDisplayValue: function answerDisplayValue() {
+ return "Effective: ".concat(TotValues.k_year, " User entered: ").concat(TotValues.user_inputted_k_year);
+ }
+};
+
+// Did the agreement or transfer include the right of publication?
+
+TotQuestions.s1q1f = {
+ // Last question in section 1, so set this if we've arrived via back button
+ section: 1,
+ question: "Did the agreement or transfer include the right of publication?",
+ explanation: 'If a transfer from 1978 or later includes the right of publication, there is a different set of rules for determining when the transfer is eligible for termination.',
+ variable: "pub_right",
+ input: "radio",
+ values: ["yes", "no", "maybe"]
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Section Two
+////////////////////////////////////////////////////////////////////////////////
+
+// Is the agreement or transfer you want to terminate part of a last will...
+
+TotQuestions.s2q2a = {
+ // First question in section 2
+ section: 2,
+ question: 'Is the agreement or transfer in question part of a last will and testament?',
+ variable: "last_will",
+ input: "radio"
+};
+
+// Are any of the authors still alive?
+
+TotQuestions.s2q2bi = {
+ question: 'Are any of the authors or artists still alive?',
+ explanation: "The copyright term for many works is based on the life of the author.",
+ variable: "any_authors_alive",
+ input: "radio"
+};
+
+// What is the year the last surviving author died?
+
+TotQuestions.s2q2bi2 = {
+ question: 'What is the year the last surviving author or artist died?',
+ explanation: "The copyright term for many works is based on the life of the author.",
+ variable: "death",
+ input: "year"
+};
+
+// Was the work created within the scope of the author’s employment?
+
+TotQuestions.s2q2c = {
+ question: 'Was the work created within the scope of the author’s employment?',
+ variable: "within_scope_of_employment",
+ input: "radio"
+};
+
+// Was there an express agreement between the author and the author's employer to not treat the work as a work made for hire?
+
+TotQuestions.s2q2ci = {
+ question: 'Was there an express agreement the author and the author\'s employer to not treat the work as a work for hire?',
+ variable: "express_agreement",
+ input: "radio"
+};
+
+// Was the work created in response to a special order or commission
+
+TotQuestions.s2q2d = {
+ question: 'Was the work created in response to a special order or commission by some other person or company?',
+ variable: "special_order",
+ input: "radio"
+};
+
+// Was there a signed written agreement regarding the special order...
+
+TotQuestions.s2q2di = {
+ question: 'Was there a signed written agreement regarding the special order or commission which explicitly refers to the work as a work for hire?',
+ variable: "signed_written_agreement",
+ input: "radio"
+};
+
+// Was the work created for use as one of the following? ...
+
+TotQuestions.s2q2dia = {
+ question: 'Was the work created for use as one of the following? —
a contribution to a collective work; a part of a motion picture or other audiovisual work;
a translation;
a supplementary work (such as a foreword, afterword, table, editorial note, musical arrangement, bibliography, appendix, or index);
',
+ variable: "created_as_part_of_motion_picture",
+ input: "radio",
+ values: ["yes", "no", "don't know"]
+};
+
+// Has the original transfer since been renegotiated or altered?
+
+TotQuestions.s2q2e = {
+ question: "Has the original transfer since been renegotiated or altered?",
+ variable: "renego",
+ input: "radio",
+ values: ["yes", "no", "don't know"]
+};
+
+// Did one or more of the authors or artists enter into the agreement...
+
+TotQuestions.s2q2f = {
+ question: 'Did one or more of the authors enter into the agreement or transfer?',
+ variable: "authors_entered_agreement",
+ input: "radio"
+};
+
+// s2q2fii is part of the rule for s2q2f
+
+// Was the agreement or transfer made by a member of...
+
+TotQuestions.s2q2fii = {
+ // Last question in section 2, so set section if we're going back
+ section: 2,
+ question: 'Was the agreement or transfer made by a member of the author\'s immediate family, or by the executors? For more information about which family members qualify, check out the FAQ.',
+ variable: "agreement_by_family_or_executor",
+ input: "radio"
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Storing answers
+////////////////////////////////////////////////////////////////////////////////
+
+TotQuestions.validateAnswer = function () {
+ var result = false;
+ var question = TotQuestions[TotQuestions.current_question];
+ if (question["validate"]) {
+ result = question.validate();
+ } else if (question.type == "year") {
+ result = TotValidation.validDate();
+ } else if (question.type == "text") {
+ // If the text has a minimum length, check it
+ if (jQuery(".text-question").val().length < question.min_chars) {
+ result = "Answer is too short, it must be at least ".concat(question.min_chars, " characters");
+ }
+ }
+ // We don't worry about radio buttons
+ return result;
+};
+TotQuestions.getAnswer = function () {
+ var question = TotQuestions[TotQuestions.current_question];
+ var answer = undefined;
+ switch (question === null || question === void 0 ? void 0 : question.input) {
+ case "radio":
+ answer = jQuery(':input[type="radio"]:checked').val();
+ break;
+ case "year":
+ if (question.optional != true || question.optional == true && jQuery(".text-question").val() != "") {
+ answer = parseInt(jQuery(".text-question").val());
+ }
+ break;
+ case "year_or_empty":
+ if (jQuery(".text-question").val() != "") {
+ answer = parseInt(jQuery(".text-question").val());
+ }
+ break;
+ case "text":
+ // Fall through to default
+ default:
+ answer = jQuery(".text-question").val();
+ break;
+ }
+ return answer;
+};
+TotQuestions.processAnswer = function () {
+ var result = false;
+ var warnings = TotQuestions.validateAnswer();
+ if (warnings === false) {
+ var question = TotQuestions[TotQuestions.current_question];
+ var answer = TotQuestions.getAnswer();
+ TotValues[question.variable] = answer;
+ // FIXME: handle converting radio buttons to correct store values
+ // while recording their label in the answers table
+ if (answer) {
+ if (typeof question.answerDisplayValue === "function") {
+ answer = question.answerDisplayValue();
+ }
+ TotAnswers.appendAnswer(question.variable, question.question, answer);
+ }
+ TotNotifications.clearAlerts();
+ result = true;
+ } else {
+ TotNotifications.setAlert(warnings);
+ }
+ return result;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Flag and result lookup
+// These messages are stored in a json file so we can also use them in the PDF
+////////////////////////////////////////////////////////////////////////////////
+
+TotQuestions.resultMap = undefined;
+// Asynchronous fetch of data that is accessed synchronously.
+// This data won't be used until after several questions, so this is tolerable.
+
+jQuery.getJSON(jQuery("script[src*='/termination-of-transfer/dist/js/questions.js']").attr("src").replace(/dist\/js\/questions\.js.*$/, "") + "assets/js/results.json").done(function (result) {
+ TotQuestions.resultMap = result;
+}).fail(function (jqxhr, textStatus, error) {
+ var err = textStatus + ", " + error;
+ console.log("Request Failed: " + err);
+});
+TotQuestions.getConclusionDetails = function (specifier) {
+ var path = specifier.split(".");
+ var result = TotQuestions.resultMap["Conclusion"][path[0]][path[1]];
+ return result;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Flow of control
+////////////////////////////////////////////////////////////////////////////////
+
+TotQuestions.first_question = "s1q1a";
+TotQuestions.last_question = "s2q2fii";
+TotQuestions.start = function () {
+ jQuery(".questionnaire-section, .question-progress-buttons").removeClass("hidden");
+ jQuery(".no-javascript-alert").addClass("hidden");
+ //TotNavigation.disablePrevious();
+ TotRendering.transitionTo(TotQuestions.first_question);
+};
+TotQuestions.transitionQuestion = function (next_question) {
+ var previous_question = TotQuestions[TotQuestions.current_question];
+ if (previous_question) {
+ if (previous_question.post) {
+ previous_question.post();
+ }
+ }
+ if (next_question == "finish") {
+ TotQuestions.finish();
+ } else {
+ TotQuestions.current_question = next_question;
+ var question = TotQuestions[TotQuestions.current_question];
+ if (question["pre"]) {
+ question.pre();
+ }
+ TotRendering.transitionTo(question);
+ }
+};
+TotQuestions.nextQuestionID = function () {
+ var next_question = TotQuestions.current_question;
+ var rule = TotRules[TotQuestions.current_question];
+ if (typeof rule == "function") {
+ next_question = rule();
+ } else {
+ next_question = rule;
+ }
+ return next_question;
+};
+TotQuestions.nextQuestion = function () {
+ // If the answer was OK, move on
+ if (TotQuestions.processAnswer()) {
+ ValuesStack.push();
+ var id = TotQuestions.nextQuestionID();
+ TotValues.question_id = id;
+ if (id == "finish") {
+ TotQuestions.finish();
+ } else {
+ TotQuestions.transitionQuestion(TotValues.question_id);
+ // Scroll down to make sure the input UI is visible
+ jQuery("html,body").animate({
+ scrollTop: jQuery("#button-question-next").offset().top
+ }, "slow");
+ }
+ }
+};
+TotQuestions.previousQuestion = function () {
+ // If we are going back from *after* the last question, re-enable UI
+ if (TotValues.question_id == "finish") {
+ TotNavigation.unfinishQuestions();
+ }
+ // Don't pop past the very first item
+ if (ValuesStack.height() > 0) {
+ // Go back
+ ValuesStack.pop();
+ TotQuestions.transitionQuestion(TotValues.question_id);
+ TotNotifications.clearAlerts();
+ // Clear previous answer
+ var previous_question = TotQuestions[TotValues.question_id];
+ TotAnswers.removeAnswer(previous_question.variable);
+ // Scroll down to make sure the input UI is visible
+ jQuery("html,body").animate({
+ scrollTop: jQuery("#button-question-next").offset().top
+ }, "slow");
+ }
+};
+TotQuestions.finish = function () {
+ var obj = TotQuestions.getConclusionDetails(TotValues.conclusion);
+ TotValues.termination_type = obj.title;
+ TotNotifications.setResultAreaMessage(obj, "panel-success");
+ TotNavigation.finishQuestions();
+ if (TotValues.conclusion_generate_pdf) {
+ TotPdf.request();
+ }
+};
+TotQuestions.start = function () {
+ TotValues.reset();
+ TotNavigation.showQuestions();
+ TotNavigation.showAnswersTable();
+ TotNavigation.showNextPrevious();
+ jQuery("#button-question-next").on("click", TotQuestions.nextQuestion);
+ jQuery("#button-question-back").on("click", TotQuestions.previousQuestion);
+ // When the user presses "return" in a text area, move to next question
+ jQuery("#question-rendering-area").on("submit", function () {
+ if (jQuery("#button-question-next").is(":enabled")) {
+ jQuery("#button-question-next").click();
+ }
+ return false;
+ });
+ TotQuestions.transitionQuestion(TotQuestions.first_question);
+ TotValues.question_id = TotQuestions.first_question;
+};
+jQuery(document).ready(function () {
+ TotQuestions.start();
+});
\ No newline at end of file
diff --git a/dist/js/rendering.js b/dist/js/rendering.js
new file mode 100644
index 0000000..709dc24
--- /dev/null
+++ b/dist/js/rendering.js
@@ -0,0 +1,148 @@
+"use strict";
+
+var _this = void 0;
+/*
+ Termination of Transfer - tool to help in returning authors rights.
+ Copyright (C) 2016 Creative Commons Corporation.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// Rendering UI elements for input
+////////////////////////////////////////////////////////////////////////////////
+
+var TotRendering = {
+ currentSection: 0,
+ sections: ["", "First tell us a few things about the work", "Now, let’s find out whether the work is eligible for termination", "Information about the work"],
+ questionTemplate: "\n ",
+ createQuestion: function createQuestion() {
+ return jQuery(TotRendering.questionTemplate);
+ },
+ common: function common(config) {
+ var question = TotRendering.createQuestion();
+ // If this is a question in a different section, change the section header
+ // Section is 1-based, so we can use a simple logical and here.
+ if (config.section && config.section != TotRendering.currentSection) {
+ jQuery("#section-title").html(TotRendering.sections[config.section]).fadeIn();
+ }
+ question.find(".question-label").html(config.question);
+ if (config.explanation) {
+ question.find(".help-block").html(config.explanation);
+ }
+ question.css("display", "none");
+ // If we're entering this value for the first time (not via the back button)
+ // and this isn't an optional value
+ // don't let the user continue until they enter a value here.
+ if (TotValues[config.variable] === undefined && !config.optional) {
+ TotNavigation.disableNext();
+ } else {
+ TotNavigation.enableNext();
+ }
+ return question;
+ },
+ radio: function radio(config) {
+ // Multiple choice questions (radio buttons)
+ var question = TotRendering.common(config);
+ var form_group = question.find(".form-group");
+ var name = "input_".concat(config.variable);
+ // If we are returning to this via the back button, get the previous value
+ var existing_value = TotValues[config.variable];
+ var radio_button_values = config.values || ["yes", "no"];
+ radio_button_values.forEach(function (value) {
+ var radio_button = "");
+ if (value == existing_value) {
+ radio_button = "");
+ }
+ form_group.append(jQuery(radio_button));
+ });
+ // When the user makes a choice, go straight to the next question
+ form_group.find(':input[type="radio"]').on("click", function () {
+ TotNavigation.enableNext();
+ jQuery("#button-question-next").click();
+ });
+ return question;
+ },
+ makeTextLengthHandler: function makeTextLengthHandler(element, min_length, optional) {
+ // text input validator handler
+ return function () {
+ var length = element.val().length;
+ if (optional && length == 0 || length >= min_length) {
+ TotNavigation.enableNext();
+ } else {
+ TotNavigation.disableNext();
+ }
+ };
+ },
+ text: function text(config) {
+ // Text input
+ var question = TotRendering.common(config);
+ var form_group = question.find(".form-group");
+ // const name = "input-" + config.variable;
+ var text_field = jQuery(""));
+ form_group.append(text_field);
+ // Set the label
+ // const label = question.find(".question-label").prop("for", name);
+ if (TotValues[config.variable]) {
+ form_group.find("text-question").val(TotValues[config.variable]);
+ }
+ var existing_value = TotValues[config.variable];
+ // Ensure next isn't enabled until enough characters are entered
+ var min_length = config.min_length || 4;
+ var text_field_element = question.find(".text-question");
+ var validator = TotRendering.makeTextLengthHandler(text_field_element, min_length, config.optional);
+ text_field_element.on("keyup", validator);
+ text_field_element.on("change", validator);
+ // If we are returning to the field and the value has already been set, use it
+ if (existing_value !== undefined) {
+ text_field.val(TotValues[config.variable]);
+ }
+ return question;
+ },
+ year: function year(config) {
+ // Year input (text subtype)
+ var question = TotRendering.text(config);
+ var text_field = question.find(".text-question");
+ TotValidation.allowOnlyNumbers(text_field);
+ text_field.prop("maxlength", 4);
+ text_field.prop("placeholder", "1977");
+ return question;
+ },
+ render: function render(config) {
+ // Render html UI from config specification
+ var result = undefined;
+ switch (config.input) {
+ case "radio":
+ result = TotRendering.radio(config);
+ break;
+ case "year":
+ result = TotRendering.year(config);
+ break;
+ case "text":
+ // Fall through to default
+ default:
+ result = TotRendering.text(config);
+ break;
+ }
+ return result;
+ },
+ transitionTo: function transitionTo(config) {
+ var question = TotRendering.render(config);
+ jQuery(".question-form").slideUp("fast", function () {
+ jQuery(_this).remove();
+ });
+ jQuery("#question-rendering-area").append(question);
+ question.slideDown("fast");
+ }
+};
diff --git a/dist/js/rules.js b/dist/js/rules.js
new file mode 100644
index 0000000..7c822c9
--- /dev/null
+++ b/dist/js/rules.js
@@ -0,0 +1,469 @@
+"use strict";
+
+/*
+ Termination of Transfer - tool to help in returning authors rights.
+ Copyright (C) 2016 Creative Commons Corporation.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+var TotRules = {};
+TotRules.simpleYesNoRule = function (variable_id, yesValue, noValue) {
+ return function () {
+ var result = undefined;
+ if (TotValues[variable_id] == "yes") {
+ result = yesValue;
+ } else {
+ result = noValue;
+ }
+ return result;
+ };
+};
+TotRules.jumpToFinish = "finish";
+TotRules.conclusion = function (conclusion) {
+ TotValues.conclusion = conclusion;
+ return TotRules.jumpToFinish;
+};
+TotRules.conclusionPDF = function (conclusion) {
+ TotRules.conclusion(conclusion);
+ TotValues.conclusion_generate_pdf = true;
+ return TotRules.jumpToFinish;
+};
+TotRules.addFlag = function (flag) {
+ TotValues.flags.push(flag);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Calculated/inferred properties
+////////////////////////////////////////////////////////////////////////////////
+
+TotRules.is203 = function () {
+ return TotValues.conclusion == "A.iii";
+};
+TotRules.is304 = function () {
+ return ["A.i", "A.ii", "A.i-ii"].indexOf(TotValues.conclusion) > -1;
+};
+TotRules.hasPublicDomainFlags = function () {
+ var result = false;
+ for (var i = 0; i < TotValues.flags.length; i++) {
+ if (TotValues.flags[i][0] == "B") {
+ result = true;
+ }
+ }
+ return result;
+};
+TotRules.beforeEndOfNoticeWindow = function () {
+ return TotValues.notice_end != undefined && TotValues.notice_end >= TotValues.current_year || TotValues.d_notice_end != undefined && TotValues.d_notice_end >= TotValues.current_year || TotValues.p_notice_end != undefined && TotValues.p_notice_end >= TotValues.current_year;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Section N Analyses
+////////////////////////////////////////////////////////////////////////////////
+
+TotRules.section304Analysis = function () {
+ // Note that this is part of the logic from the section 203 analysis
+ var result = "s1q1f";
+ if (TotValues.k_year < 1978) {
+ result = "s2q2a";
+ TotRules.addFlag("F.i");
+ if (TotValues.pub_year > 1977 && TotValues.reg_year > 1977) {
+ result = TotRules.conclusion("B.vii");
+ } else {
+ // Under the 1909 Act, copyright term begins at the earlier of
+ // the registration date and the publication date.
+ // If the work is both registered and published use the minimum of them.
+ if (TotValues.reg_year != undefined && TotValues.pub_year != undefined) {
+ TotValues.cright_year = Math.min(TotValues.pub_year, TotValues.reg_year);
+ }
+ // Otherwise use whichever value is set. One *will* be set here, see top.
+ else {
+ TotValues.cright_year = TotValues.reg_year || TotValues.pub_year;
+ }
+ TotValues.cright_year = Math.min(TotValues.cright_year, 1978);
+ TotValues.term_begin = TotValues.cright_year + 56;
+ TotValues.term_begin = Math.max(TotValues.term_begin, 1978);
+ TotValues.term_end = TotValues.term_begin + 5;
+ TotValues.notice_begin = TotValues.term_begin - 10;
+ TotValues.notice_end = TotValues.term_end - 2;
+ // If the we're presently before the 304(c) window, then we don't have to worry about 304(d)
+ if (TotValues.notice_begin > TotValues.current_year) {
+ TotRules.addFlag("A.i.a");
+ // Following Copyright Office guidance, works copyrighted before 1940 may also be eligible for termination under 304d
+ } else if (TotValues.cright_year < 1940) {
+ TotRules.addFlag("F.ii");
+ TotValues.d_term_begin = TotValues.term_begin + 19;
+ TotValues.d_term_end = TotValues.d_term_begin + 5;
+ TotValues.d_notice_begin = TotValues.d_term_begin - 10;
+ TotValues.d_notice_end = TotValues.d_term_end - 2;
+ if (TotValues.cright_year > 1936) {
+ TotRules.addFlag("G.i");
+ }
+ if (TotValues.cright_year == 1939) {
+ TotRules.addFlag("G.ii.a");
+ }
+ if (TotValues.d_notice_begin > TotValues.current_year) {
+ // time traveler flag -- applies where the present day is between
+ // the 304(c) and 304(d) notice windows
+ TotRules.addFlag("A.iii.a");
+ } else if (TotValues.d_notice_end < TotValues.current_year) {
+ TotRules.addFlag("A.ii.a");
+ }
+ } else if (TotValues.notice_end < TotValues.current_year) {
+ TotRules.addFlag("A.ii.a");
+ } else {
+ // Here for clarity / to reflect decision tree structure
+ // But note that we set it as the result above.
+ result = "s2q2a";
+ }
+ }
+ if (TotValues.d_term_begin != undefined && TotValues.term_begin != undefined) {
+ TotRules.addFlag("E.i");
+ }
+ }
+ return result;
+};
+TotRules.section203Analysis = function () {
+ var result = "s2q2a";
+ if (typeof TotValues.grant_pub_year !== "undefined") {
+ TotRules.addFlag("F.iv");
+ }
+ TotValues.triggering_pub_year = TotValues.grant_pub_year || TotValues.pub_year;
+ if (TotValues.k_year > 1977) {
+ TotRules.addFlag("F.iii");
+ if (TotValues.pub_right == "yes") {
+ if (TotValues.triggering_pub_year != undefined) {
+ TotValues.term_begin = Math.min(TotValues.triggering_pub_year + 35, TotValues.k_year + 40);
+ } else {
+ TotValues.term_begin = TotValues.k_year + 40;
+ }
+ } else if (TotValues.triggering_pub_year != TotValues.k_year || TotValues.pub_right == "no") {
+ TotValues.term_begin = TotValues.k_year + 35;
+ }
+ if (TotValues.term_begin != undefined) {
+ TotValues.term_end = TotValues.term_begin + 5;
+ TotValues.notice_begin = TotValues.term_begin - 10;
+ TotValues.notice_end = TotValues.term_end - 2;
+ if (TotValues.notice_begin > TotValues.current_year) {
+ TotRules.addFlag("A.i.a");
+ } else if (TotValues.notice_end < TotValues.current_year) {
+ TotRules.addFlag("A.ii.a");
+ }
+ }
+ if (TotValues.pub_right == "maybe") {
+ TotValues.p_term_begin = TotValues.k_year + 40;
+ if (TotValues.triggering_pub_year != undefined) {
+ TotValues.p_term_begin = Math.min(TotValues.triggering_pub_year + 35, TotValues.p_term_begin);
+ }
+ TotValues.p_term_end = TotValues.p_term_begin + 5;
+ TotValues.p_notice_begin = TotValues.p_term_begin - 10;
+ TotValues.p_notice_end = TotValues.p_term_end - 2;
+ if (TotValues.p_notice_begin > TotValues.current_year) {
+ TotRules.addFlag("A.i.a");
+ } else if (TotValues.p_notice_end < TotValues.current_year) {
+ TotRules.addFlag("A.ii.a");
+ }
+ }
+ }
+ if (TotValues.p_term_begin != undefined && TotValues.term_begin != undefined) {
+ TotRules.addFlag("E.ii");
+ }
+ return result;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Section 1
+////////////////////////////////////////////////////////////////////////////////
+
+// When was the work created?
+
+TotRules.s1q1a = "s1q1b";
+
+// Has the work been published?
+
+TotRules.s1q1b = TotRules.simpleYesNoRule("work_published", "s1q1bi", "s1q1c");
+
+// When was the work first published?
+
+TotRules.s1q1bi = "s1q1bii";
+
+// When was the work first published under the grant?
+// Note that the condition is based on s1q1b, we are inserting this question
+// after 'When was the work first published?' and *then* going on to the
+// questions about registration/notices or not.
+
+TotRules.s1q1bii = function () {
+ var result = undefined;
+ if (TotValues.pub_year < 1923) {
+ result = TotRules.conclusion("B.viii");
+ } else if (TotValues.pub_year < 1990) result = "s1q1bi2";else {
+ result = "s1q1d";
+ }
+ return result;
+};
+
+// Works from 1989 and earlier usually display a copyright notice...
+
+TotRules.s1q1bi2 = function () {
+ var result = undefined;
+ if (TotValues.copyright_notice == "yes") {
+ result = "s1q1c";
+ } else if (TotValues.copyright_notice == "no") {
+ // The same
+ result = "s1q1c";
+ if (TotValues.pub_year < 1989) {
+ TotRules.addFlag("B.i");
+ } else {
+ TotRules.addFlag("B.ii");
+ }
+ } /* maybe */else {
+ result = "s1q1c";
+ TotRules.addFlag("B.iii");
+ }
+ return result;
+};
+
+// Has the work been registered with the United State Copyright Office?
+
+TotRules.s1q1c = function () {
+ var result = undefined;
+ if (TotValues.work_registered == "yes") {
+ result = "s1q1ci";
+ } else if (TotValues.work_registered == "no") {
+ result = "s1q1d";
+ } /* don't know */else {
+ // If someone doesn't know, continue without asking for registration number
+ result = "s1q1d";
+ }
+ return result;
+};
+
+// When was the work registered with the United States Copyright Office?
+
+TotRules.s1q1ci = function () {
+ var result = undefined;
+ if (TotValues.reg_year < 1923) {
+ result = TotRules.conclusion("B.viii");
+ } else {
+ result = "s1q1d";
+ }
+ return result;
+};
+
+// For s1q1d,
+// What is the date of the agreement or transfer? ...
+
+TotRules.s1q1d = function () {
+ var result = undefined;
+ if (TotValues.user_inputted_k_year != TotValues.k_year) {
+ TotRules.addFlag("H.i");
+ }
+ if (TotValues.k_year < 1978 && TotValues.pub_year == undefined && TotValues.reg_year == undefined) {
+ result = TotRules.conclusion("B.vii");
+ } else {
+ // Intercept the result so we can add encouragement if things look good
+ result = TotRules.section304Analysis();
+ if (result != TotRules.jumpToFinish && TotRules.beforeEndOfNoticeWindow() && !TotRules.hasPublicDomainFlags()) {
+ TotNotifications.setEncouragement("Both notice window and copyright status look good, let's get some more details!");
+ }
+ }
+ return result;
+};
+
+// Did the agreement or transfer include the right of publication?
+
+TotRules.s1q1f = function () {
+ // Intercept the result so we can add encouragement if things look good
+ var result = TotRules.section203Analysis();
+ if (result != TotRules.jumpToFinish && TotRules.beforeEndOfNoticeWindow() && !TotRules.hasPublicDomainFlags()) {
+ TotNotifications.setEncouragement("Both notice window and copyright status look good, let's get some more details!");
+ }
+ return result;
+};
+TotRules.section203Analysis;
+
+////////////////////////////////////////////////////////////////////////////////
+// Section 2
+////////////////////////////////////////////////////////////////////////////////
+
+// Is the agreement or transfer you want to terminate part of a last will...
+
+TotRules.s2q2a = function () {
+ var result = undefined;
+ if (TotValues.last_will == "yes") {
+ result = TotRules.conclusion("B.iv");
+ } else {
+ if (TotValues.creation_year > 1977 || (TotValues.pub_year == undefined || TotValues.pub_year > 1977) && (TotValues.reg_year == undefined || TotValues.reg_year > 1977)) {
+ result = "s2q2bi";
+ } else {
+ result = "s2q2c";
+ }
+ }
+ return result;
+};
+
+// Are any of the authors still alive?
+// It's i) because the conditional logic that starts b is included in a
+
+TotRules.s2q2bi = function () {
+ var result = undefined;
+ if (TotValues.any_authors_alive == "yes") {
+ result = "s2q2c";
+ } else {
+ result = "s2q2bi2";
+ }
+ return result;
+};
+
+// What is the year the last surviving author died?
+
+TotRules.s2q2bi2 = function () {
+ var result = undefined;
+ // creation_year is always set, pub_year may not be, death will be here
+ if (TotValues.creation_year > 1977) {
+ TotValues.pd = TotValues.death + 71;
+ } else if (TotValues.pub_year != undefined && TotValues.pub_year < 2003) {
+ TotValues.pd = Math.max(TotValues.death + 71, 2048);
+ } else {
+ TotValues.pd = Math.max(TotValues.death + 71, 2003);
+ }
+ // pd *will* have been set in the if/else block
+ if (TotValues.current_year > TotValues.pd) {
+ result = TotRules.conclusion("B.viii");
+ } else {
+ result = "s2q2c";
+ }
+ return result;
+};
+
+// Was the work created within the scope of the author’s employment?
+
+TotRules.s2q2c = function () {
+ var result = undefined;
+ if (TotValues.within_scope_of_employment == "yes") {
+ if (TotValues.creation_year > 1977) {
+ result = "s2q2ci";
+ } else {
+ result = TotRules.conclusion("B.i");
+ }
+ } else {
+ result = "s2q2d";
+ }
+ return result;
+};
+
+// Was there an express agreement between you...
+
+TotRules.s2q2ci = function () {
+ var result = undefined;
+ if (TotValues.express_agreement == "yes") {
+ result = "s2q2d";
+ } else {
+ result = TotRules.conclusion("B.i");
+ }
+ return result;
+};
+
+// Was the work created in response to a special order or commission?
+
+TotRules.s2q2d = function () {
+ var result = undefined;
+ if (TotValues.special_order == "yes") {
+ if (TotValues.creation_year < 1978) {
+ TotRules.addFlag("D.i");
+ result = "s2q2e";
+ } else {
+ result = "s2q2di";
+ }
+ } else {
+ result = "s2q2e";
+ }
+ return result;
+};
+
+// Was there a signed written agreement regarding the special order...
+
+TotRules.s2q2di = function () {
+ var result = undefined;
+ if (TotValues.signed_written_agreement == "yes") {
+ if (TotValues.creation_year < 1978) {
+ result = TotRules.conclusion("B.iii");
+ } else {
+ result = "s2q2dia";
+ }
+ } else {
+ result = "s2q2e";
+ }
+ return result;
+};
+
+// Was the work created for use as one of the following? ...
+
+TotRules.s2q2dia = function () {
+ var result = undefined;
+ if (TotValues.created_as_part_of_motion_picture == "yes") {
+ result = TotRules.conclusion("C.ii");
+ } else if (TotValues.created_as_part_of_motion_picture == "no") {
+ result = "s2q2e";
+ } /* don't know */else {
+ TotRules.addFlag("D.ii");
+ result = "s2q2e";
+ }
+ return result;
+};
+
+// Has the original transfer since been renegotiated or altered?
+
+TotRules.s2q2e = function () {
+ var result = "s2q2f";
+ if (TotValues.renego == "yes") {
+ TotRules.addFlag("C.i");
+ } else if (TotValues.renego == "no") {
+ // Continue
+ } /* don't know */else {
+ TotRules.addFlag("C.ii");
+ }
+ return result;
+};
+
+// Did one or more of the authors or artists enter into the agreement...
+
+TotRules.s2q2f = function () {
+ var result = undefined;
+ if (TotValues.authors_entered_agreement == "yes") {
+ if (TotValues.k_year < 1978) {
+ result = TotRules.conclusionPDF("A.i-ii");
+ } /*if (k_year > 1977)*/else {
+ result = TotRules.conclusionPDF("A.iii");
+ }
+ } else {
+ if (TotValues.k_year < 1978) {
+ result = "s2q2fii";
+ } /*if (TotValues.k_year > 1977)*/else {
+ result = TotRules.conclusion("B.vi");
+ }
+ }
+ return result;
+};
+
+// Was the agreement or transfer made by a member of...
+
+TotRules.s2q2fii = function () {
+ var result = undefined;
+ if (TotValues.agreement_by_family_or_executor) {
+ result = TotRules.conclusionPDF("A.i-ii");
+ } else {
+ result = TotRules.conclusion("B.v");
+ }
+ return result;
+};
\ No newline at end of file
diff --git a/wordpress-plugin/js/validation.js b/dist/js/validation.js
similarity index 67%
rename from wordpress-plugin/js/validation.js
rename to dist/js/validation.js
index 67e58c2..d660eb2 100644
--- a/wordpress-plugin/js/validation.js
+++ b/dist/js/validation.js
@@ -1,3 +1,6 @@
+"use strict";
+
+var _this = void 0;
/*
Termination of Transfer - tool to help in returning authors rights.
Copyright (C) 2016 Creative Commons Corporation.
@@ -17,32 +20,30 @@
*/
////////////////////////////////////////////////////////////////////////////////
-// Validation of values and of UI state
+// TotValidation of values and of UI state
////////////////////////////////////////////////////////////////////////////////
-var Validation = {};
+var TotValidation = {};
// Naughty. If we're going to monkeypatch we should have a file for these
-String.prototype.capitalizeFirstLetter = function() {
- return this.charAt(0).toUpperCase() + this.slice(1);
-}
-
-Validation.allowOnlyNumbers = function (element) {
+String.prototype.capitalizeFirstLetter = function () {
+ return _this.charAt(0).toUpperCase() + _this.slice(1);
+};
+TotValidation.allowOnlyNumbers = function (element) {
// http://stackoverflow.com/a/995193
element.keydown(function (e) {
// Allow: backspace, delete, tab, escape, enter and .
if (jQuery.inArray(e.keyCode, [46, 8, 9, 27, 13, 110, 190]) !== -1 ||
- // Allow: Ctrl+A, Command+A
- (e.keyCode == 65 && ( e.ctrlKey === true || e.metaKey === true ) ) ||
- // Allow: home, end, left, right, down, up
- (e.keyCode >= 35 && e.keyCode <= 40)) {
+ // Allow: Ctrl+A, Command+A
+ e.keyCode == 65 && (e.ctrlKey === true || e.metaKey === true) ||
+ // Allow: home, end, left, right, down, up
+ e.keyCode >= 35 && e.keyCode <= 40) {
// let it happen, don't do anything
return;
}
// Ensure that it is a number and stop the keypress
- if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57))
- && (e.keyCode < 96 || e.keyCode > 105)) {
+ if ((e.shiftKey || e.keyCode < 48 || e.keyCode > 57) && (e.keyCode < 96 || e.keyCode > 105)) {
e.preventDefault();
}
});
@@ -50,19 +51,19 @@ Validation.allowOnlyNumbers = function (element) {
// false here means no errors, a string means errors
-Validation.validDate = function () {
- var text_field = jQuery('.text-question');
+TotValidation.validDate = function () {
+ var text_field = jQuery(".text-question");
var date = text_field.val();
var result = false;
var errors = [];
- if (! date.match(/[0-9]{4}/)) {
+ if (!date.match(/[0-9]{4}/)) {
errors.push("date must be four digits");
}
- if (parseInt(date) > Values.current_year) {
+ if (parseInt(date) > TotValues.current_year) {
errors.push("date must be in the past");
}
if (errors.length != 0) {
- result = errors.join().capitalizeFirstLetter() + '.';
+ result = "".concat(errors.join().capitalizeFirstLetter(), ".");
}
return result;
};
diff --git a/wordpress-plugin/js/values.js b/dist/js/values.js
similarity index 62%
rename from wordpress-plugin/js/values.js
rename to dist/js/values.js
index 6952c06..a598b00 100644
--- a/wordpress-plugin/js/values.js
+++ b/dist/js/values.js
@@ -1,3 +1,5 @@
+"use strict";
+
/*
Termination of Transfer - tool to help in returning authors rights.
Copyright (C) 2016 Creative Commons Corporation.
@@ -22,11 +24,10 @@
// Rules consult these values and add their own.
////////////////////////////////////////////////////////////////////////////////
-var Values = {};
-
-Values.reset = function () {
+var TotValues = {};
+TotValues.reset = function () {
var now = new Date();
- Values = {
+ TotValues = {
current_date: now,
current_year: now.getFullYear(),
flags: []
@@ -35,40 +36,36 @@ Values.reset = function () {
//FIXME: Hello namespace pollution
-var varsToTitles = {
- work_authors: 'Author',
- work_title: 'Title of Work',
- creation_year: 'Creation Year',
- pub_year: 'Publication Year',
- grant_pub_year: 'Publication Year Under Grant',
- triggering_pub_year: 'Triggering Publication Date',
- k_year: 'Effective Grant Year',
- user_inputted_k_year: 'User Entered Grant Year',
- reg_year: 'Copyright Registration Year',
- work_copyright_reg_num: 'Registration Number',
- termination_type: 'Termination Type',
- work_agreement_type: 'Agreement or Transfer Type',
- work_agreement_desc: 'Agreement or Transfer Description',
+var totVarsToTitles = {
+ work_authors: "Author",
+ work_title: "Title of Work",
+ creation_year: "Creation Year",
+ pub_year: "Publication Year",
+ grant_pub_year: "Publication Year Under Grant",
+ triggering_pub_year: "Triggering Publication Date",
+ k_year: "Effective Grant Year",
+ user_inputted_k_year: "User Entered Grant Year",
+ reg_year: "Copyright Registration Year",
+ work_copyright_reg_num: "Registration Number",
+ termination_type: "Termination Type",
+ work_agreement_type: "Agreement or Transfer Type",
+ work_agreement_desc: "Agreement or Transfer Description"
//'': 'Grantor',
};
var ValuesStack = {};
-
ValuesStack._stack = [];
-
ValuesStack.height = function () {
- return this._stack.length;
+ return ValuesStack._stack.length;
};
-
ValuesStack.push = function () {
// Handle the date not liking being serialized.
- var now = Values.current_date;
- this._stack.push(Values);
+ var now = TotValues.current_date;
+ ValuesStack._stack.push(TotValues);
// Deep clone
- Values = JSON.parse(JSON.stringify(Values));
- Values.current_date = now;
+ TotValues = JSON.parse(JSON.stringify(TotValues));
+ TotValues.current_date = now;
};
-
ValuesStack.pop = function () {
- Values = this._stack.pop();
+ TotValues = ValuesStack._stack.pop();
};
diff --git a/dist/js/widgets.js b/dist/js/widgets.js
new file mode 100644
index 0000000..7ffc20e
--- /dev/null
+++ b/dist/js/widgets.js
@@ -0,0 +1,134 @@
+"use strict";
+
+/*
+ Termination of Transfer - tool to help in returning authors rights.
+ Copyright (C) 2016 Creative Commons Corporation.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// Control of the html UI
+////////////////////////////////////////////////////////////////////////////////
+
+//var Widgets = {};
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual display of the user's responses
+////////////////////////////////////////////////////////////////////////////////
+
+var TotAnswers = {};
+TotAnswers.resetAnswers = function () {
+ jQuery("#answers-table-rows").empty();
+};
+TotAnswers.appendAnswer = function (myId, label, value) {
+ if (!label) {
+ label = jQuery("#".concat(myId)).parent().find("label").first().text();
+ }
+ // If the user has gone back and is changing the answer, first remove it
+ TotAnswers.removeAnswer(myId);
+ jQuery("#answers-table-rows").append("
").concat(label, "
").concat(value, "
"));
+};
+TotAnswers.removeAnswer = function (myId) {
+ jQuery("#answer-row-".concat(myId)).remove();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Notifications and other notices
+////////////////////////////////////////////////////////////////////////////////
+
+var TotNotifications = {};
+TotNotifications.clearAlerts = function () {
+ jQuery("#alert-area").empty();
+};
+TotNotifications.setAlert = function (message) {
+ TotNotifications.clearAlerts();
+ jQuery("#alert-area").append("
', wpautop( $message ) );
+ echo wp_kses_post( $html_message );
+ }
+
+ /**
+ * Notice for minimum WordPress version.
+ *
+ * Warning when the site does not meet the minimum required WordPress version.
+ *
+ * @return void
+ */
+ public function failWpVersion() {
+ /* translators: %s: WordPress version */
+ $v = $this->data['version'];
+ $n = $this->data['name'];
+ $message = sprintf( "Version $v of $n requires WordPress version %s+. Because you are using an earlier version, the plugin is currently NOT RUNNING", '4.0' );
+ $html_message = sprintf( '
%s
', wpautop( $message ) );
+ echo wp_kses_post( $html_message );
+ }
+}
diff --git a/src/WpPlugin.php b/src/WpPlugin.php
new file mode 100644
index 0000000..9a33fb4
--- /dev/null
+++ b/src/WpPlugin.php
@@ -0,0 +1,69 @@
+data = [];
+ }
+
+ /**
+ * The HTML code to display
+ *
+ * @return String The HTML string
+ */
+ public function generateHtml()
+ {
+ $tot_tool_html = <<<'EOD'
+
-EOD;
-
-
-//[termination-of-transfer-tool]
-function tot_tool_handle_shortcode( $atts ){
- global $tot_tool_html;
- wp_enqueue_script("jquery");
- wp_enqueue_script( 'tot-values',
- plugins_url( 'js/values.js', __FILE__ ) );
- wp_enqueue_script( 'tot-rules',
- plugins_url( 'js/rules.js', __FILE__ ) );
- wp_enqueue_script( 'tot-validation',
- plugins_url( 'js/validation.js', __FILE__ ) );
- wp_enqueue_script( 'tot-widgets',
- plugins_url( 'js/widgets.js', __FILE__ ) );
- wp_enqueue_script( 'tot-rendering',
- plugins_url( 'js/rendering.js', __FILE__ ) );
- wp_enqueue_script( 'tot-pdf',
- plugins_url( 'js/pdf.js', __FILE__ ) );
- wp_enqueue_script( 'tot-questions',
- plugins_url( 'js/questions.js', __FILE__ ) );
- return $tot_tool_html;
-}
-
-add_shortcode( 'termination-of-transfer-tool',
- 'tot_tool_handle_shortcode' );
diff --git a/wordpress-plugin/js/pdf.js b/wordpress-plugin/js/pdf.js
deleted file mode 100644
index 5748eee..0000000
--- a/wordpress-plugin/js/pdf.js
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- Termination of Transfer - tool to help in returning authors rights.
- Copyright (C) 2016 Creative Commons Corporation.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-////////////////////////////////////////////////////////////////////////////////
-// PDF Generation
-// (browser-side data preparation and call to server)
-////////////////////////////////////////////////////////////////////////////////
-
-var PDF = {};
-
-PDF.url = jQuery("script[src*='/termination-of-transfer/js/pdf.js']")
- .attr('src').replace(/js\/pdf\.js.*$/, '')
- + 'result-pdf.php';
-
-PDF.appendProperty = function (details, key, value) {
- var mapping = {key: key,
- value: value};
- details.push(mapping);
-};
-
-PDF.append203Windows = function (details) {
- var notice = '';
- var termination = '';
-
- if (Values.notice_begin != undefined) {
- notice += Values.notice_begin + '-' + Values.notice_end;
- termination += Values.term_begin + '-' + Values.term_end
- }
-
- if (Values.p_term_begin != undefined) {
- if (notice != '') {
- notice += ' or ';
- termination += ' or ';
- }
- notice += Values.p_notice_begin + '-' + Values.p_notice_end;
- termination += Values.p_term_begin + '-' + Values.p_term_end;
- }
-
- PDF.appendProperty(details, '§ 203 notice window', notice);
- PDF.appendProperty(details, '§ 203 termination window', termination);
-};
-
-PDF.append304Windows = function (details) {
- PDF.appendProperty(details, '§ 304(c) notice window begins',
- Values.notice_begin);
- PDF.appendProperty(details, '§ 304(c) notice window ends',
- Values.notice_end);
- PDF.appendProperty(details, '§ 304(c) termination window begins',
- Values.term_begin);
- PDF.appendProperty(details, '§ 304(c) termination window ends',
- Values.term_end);
- if (Values.d_notice_begin != undefined) {
- PDF.appendProperty(details, '§ 304(d) notice window begins',
- Values.d_notice_begin);
- PDF.appendProperty(details, '§ 304(d) notice window ends',
- Values.d_notice_end);
- PDF.appendProperty(details, '§ 304(d) termination window begins',
- Values.d_term_begin);
- PDF.appendProperty(details, '§ 304(d) termination window ends',
- Values.d_term_end);
- }
-};
-
-PDF.appendWindows = function (details) {
- if (Rules.is203()) {
- PDF.append203Windows(details);
- } else if (Rules.is304()) {
- PDF.append304Windows(details);
- }
-};
-
-PDF.details = function () {
- var details = [];
- Object.getOwnPropertyNames(varsToTitles).forEach(function (key) {
- if ((Values[key] != undefined)
- && (Values[key] != '')) {
- PDF.appendProperty(details, varsToTitles[key], Values[key]);
- }
- });
- PDF.appendWindows(details);
- return details;
-};
-
-PDF.request = function () {
- var data = {report_timestamp: Values.current_date.getTime()/1000,
- flags: Values.flags.sort(), // Sorts inline & returns, so OK here
- conclusion: Values.conclusion,
- details: PDF.details(),
- };
- var totform = document.createElement("FORM");
- totform.setAttribute("action", PDF.url);
- totform.setAttribute("method", "post");
- totform.setAttribute("enctype", "multipart/form-data");
- totform.setAttribute("target", "_blank");
- var data_field = document.createElement("INPUT");
- data_field.setAttribute("type", "hidden");
- data_field.setAttribute("name", "data");
- data_field.setAttribute("value", JSON.stringify(data));
- totform.appendChild(data_field);
- jQuery('body').append(totform);
- totform.submit();
-};
diff --git a/wordpress-plugin/js/questions.js b/wordpress-plugin/js/questions.js
deleted file mode 100644
index ad73a51..0000000
--- a/wordpress-plugin/js/questions.js
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- Termination of Transfer - tool to help in returning authors rights.
- Copyright (C) 2016 Creative Commons Corporation.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-////////////////////////////////////////////////////////////////////////////////
-// Presentation of questions, and main flow of control
-// (This is slightly overloaded)
-////////////////////////////////////////////////////////////////////////////////
-
-var Questions = {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Section One
-////////////////////////////////////////////////////////////////////////////////
-
-// When was the work created?
-
-Questions.s1q1a = {
- section: 1,
- question: 'When was the work created?',
- explanation:'The year in which a work was created can affect its copyright status and its treatment under U.S. copyright law. Most importantly, the tool is concerned with whether a worked was made before or after January 1, 1978, when the most recent overhaul of U.S. copyright went into effect.',
- variable: 'creation_year',
- input: 'year',
- pre: function () {
- Navigation.disablePrevious();
- Notifications.displayAnswersHint();
- },
- post: function () {
- Notifications.removeAnswersHint();
- }
-};
-
-// Has the work been published?
-
-Questions.s1q1b = {
- question: 'Has the work been published?',
- explanation:'Whether a work has been published can affect its copyright status and factor into the timing of a termination right. Note that "publication" has a particular meaning in U.S. copyright law, as discussed in our glossary.',
- variable: 'work_published',
- input: 'radio',
- pre: function () {
- Navigation.enablePrevious();
- }
-};
-
-// When was the work first published?
-
-Questions.s1q1bi = {
- variable: 'pub_year',
- question: 'When was the work first published?',
- explanation:'When a work was published can affect its copyright status and factor into the timing of a termination right. Note that "publication" has a particular meaning in U.S. copyright law, as discussed in our glossary.',
- input: 'year',
- validate: function () {
- return Validation.validDate()
- || ((parseInt(jQuery('.text-question').val()) < Values.creation_year)
- ? 'The publication year cannot be earlier than the creation year.'
- : false);
- }
-
-};
-
-// When was the work first published under the grant?
-
-Questions.s1q1bii = {
- section: 1,
- question: 'When was the work first published under the grant?',
- explanation:'When a work was first published under the grant (which may be different than the the date the work was published for the first time) can factor into the timing of a termination right. Note that "publication" has a particular meaning in U.S. copyright law, as discussed in our glossary.',
- variable: 'grant_pub_year',
- input: 'year',
- validate: function () {
- var errors = Validation.validDate();
- if (errors == false) {
- var year = parseInt(jQuery('.text-question').val());
- if (year < Values.creation_year) {
- errors = 'Year of publication under grant cannot be earlier than year of creation.';
- } else if (year < Values.pub_year) {
- errors = 'Year of publication under grant cannot be earlier than year of initial publication.';
- } /* else if (year < Values.k_year) {
- errors = 'Year of publication under grant cannot be earlier than year of grant.';
- }*/
- }
- return errors;
- }
-};
-
-
-// Works from 1989 and earlier usually display a copyright notice. Did the work have a copyright notice?
-
-Questions.s1q1bi2 = {
- question: 'Published works from 1989 and earlier usually display a copyright notice. Did the work have a copyright notice?',
- explanation:'For U.S. works published in certain years, U.S. law required that they feature a "copyright notice" in order to receive federal copyright protection. Whether or not the published version featured a copyright notice can affect the copyright status of these works.',
- variable: 'copyright_notice',
- input: 'radio',
- values: ['yes', 'no', 'maybe']
-};
-
-// Has the work been registered with the United State Copyright Office?
-
-Questions.s1q1c = {
- question: 'Has the work been registered with the United State Copyright Office?',
- explanation:'Before 1989, registration was one of the ways authors could secure federal copyright in their work. Whether a work was registered can affect copyright status and the timing of termination right.',
- variable: 'work_registered',
- input: 'radio',
- values: ['yes', 'no'] //, "don't know"] GitHub issue #33
-};
-
-// When was the work registered with the United States Copyright Office?
-
-Questions.s1q1ci = {
- question: 'When was the work registered with the United States Copyright Office?',
- explanation:'Before 1989, registration was one of the ways authors could secure federal copyright in their work. When a work was registered can affect copyright status and the timing of termination right.',
- variable: 'reg_year',
- input: 'year'
-};
-
-// What is the date of the agreement or transfer? ...
-
-Questions.s1q1d = {
- question: 'What is the year of the agreement or transfer?',
- explanation:'When a transfer took place determines the particular set of termination rules that will be applicable. The timing of a transfer is also needed to know when a work\'s copyright transfer may be eligible for termination.',
- variable: 'k_year',
- input: 'year',
- validate: function () {
- var errors = Validation.validDate();
- if (errors == false) {
- // Stash the user-entered agreement year
- Values.user_inputted_k_year = parseInt(jQuery('.text-question').val());
- // If date is before the creation year, use the creation year instead
- if (Values.user_inputted_k_year < Values.creation_year) {
- jQuery('.text-question').val(Values.creation_year);
- }
- }
- return errors;
- },
- answerDisplayValue: function () {
- return "Effective: " + Values.k_year + " User entered: "
- + Values.user_inputted_k_year;
- }
-};
-
-// Did the agreement or transfer include the right of publication?
-
-Questions.s1q1f = {
- // Last question in section 1, so set this if we've arrived via back button
- section: 1,
- question: 'Did the agreement or transfer include the right of publication?',
- explanation:'If a transfer from 1978 or later includes the right of publication, there is a different set of rules for determining when the transfer is eligible for termination.',
- variable: 'pub_right',
- input: 'radio',
- values: ['yes', 'no', 'maybe']
-};
-
-
-////////////////////////////////////////////////////////////////////////////////
-// Section Two
-////////////////////////////////////////////////////////////////////////////////
-
-// Is the agreement or transfer you want to terminate part of a last will...
-
-Questions.s2q2a = {
- // First question in section 2
- section: 2,
- question: 'Is the agreement or transfer in question part of a last will and testament?',
- variable: 'last_will',
- input: 'radio'
-};
-
-// Are any of the authors still alive?
-
-Questions.s2q2bi = {
- question: 'Are any of the authors or artists still alive?',
- explanation:'The copyright term for many works is based on the life of the author.',
- variable: 'any_authors_alive',
- input: 'radio'
-};
-
-// What is the year the last surviving author died?
-
-Questions.s2q2bi2 = {
- question: 'What is the year the last surviving author or artist died?',
- explanation:'The copyright term for many works is based on the life of the author.',
- variable: 'death',
- input: 'year'
-};
-
-// Was the work created within the scope of the author’s employment?
-
-Questions.s2q2c = {
- question: 'Was the work created within the scope of the author’s employment?',
- variable: 'within_scope_of_employment',
- input: 'radio'
-};
-
-// Was there an express agreement between the author and the author's employer to not treat the work as a work made for hire?
-
-Questions.s2q2ci = {
- question: 'Was there an express agreement the author and the author\'s employer to not treat the work as a work for hire?',
- variable: 'express_agreement',
- input: 'radio'
-};
-
-// Was the work created in response to a special order or commission
-
-Questions.s2q2d = {
- question: 'Was the work created in response to a special order or commission by some other person or company?',
- variable: 'special_order',
- input: 'radio'
-};
-
-// Was there a signed written agreement regarding the special order...
-
-Questions.s2q2di = {
- question: 'Was there a signed written agreement regarding the special order or commission which explicitly refers to the work as a work for hire?',
- variable: 'signed_written_agreement',
- input: 'radio'
-};
-
-// Was the work created for use as one of the following? ...
-
-Questions.s2q2dia = {
- question: 'Was the work created for use as one of the following? —
a contribution to a collective work; a part of a motion picture or other audiovisual work;
a translation;
a supplementary work (such as a foreword, afterword, table, editorial note, musical arrangement, bibliography, appendix, or index);
',
- variable: 'created_as_part_of_motion_picture',
- input: 'radio',
- values: ["yes", "no", "don't know"]
-};
-
-// Has the original transfer since been renegotiated or altered?
-
-Questions.s2q2e = {
- question: 'Has the original transfer since been renegotiated or altered?',
- variable: 'renego',
- input: 'radio',
- values: ["yes", "no", "don't know"]
-};
-
-// Did one or more of the authors or artists enter into the agreement...
-
-Questions.s2q2f = {
- question: 'Did one or more of the authors enter into the agreement or transfer?',
- variable: 'authors_entered_agreement',
- input: 'radio'
-};
-
-// s2q2fii is part of the rule for s2q2f
-
-// Was the agreement or transfer made by a member of...
-
-Questions.s2q2fii = {
- // Last question in section 2, so set section if we're going back
- section: 2,
- question: 'Was the agreement or transfer made by a member of the author\'s immediate family, or by the executors? For more information about which family members qualify, check out the FAQ.',
- variable: 'agreement_by_family_or_executor',
- input: 'radio'
-};
-
-
-////////////////////////////////////////////////////////////////////////////////
-// Storing answers
-////////////////////////////////////////////////////////////////////////////////
-
-Questions.validateAnswer = function () {
- var result = false;
- var question = Questions[Questions.current_question];
- if (question['validate']) {
- result = question.validate();
- } else if (question.type == 'year') {
- result = Validation.validDate();
- } else if (question.type == 'text') {
- // If the text has a minimum length, check it
- if (jQuery('.text-question').val().length < question.min_chars) {
- result = 'Answer is too short, it must be at least '
- + question.min_chars + 'characters';
- }
- }
- // We don't worry about radio buttons
- return result
-};
-
-Questions.getAnswer = function () {
- var question = Questions[Questions.current_question];
- var answer = undefined;
- switch (question.input) {
- case 'radio':
- answer = jQuery(':input[type="radio"]:checked').val();
- break;
- case 'year':
- if ((question.optional != true)
- || ((question.optional == true)
- && jQuery('.text-question').val() != '')) {
- answer = parseInt(jQuery('.text-question').val());
- }
- break;
- case 'year_or_empty':
- if (jQuery('.text-question').val() != '') {
- answer = parseInt(jQuery('.text-question').val());
- }
- break;
- case 'text':
- // Fall through to default
- default:
- answer = jQuery('.text-question').val();
- break;
- }
- return answer;
-};
-
-Questions.processAnswer = function () {
- var result = false;
- var warnings = Questions.validateAnswer();
- if (warnings === false) {
- var question = Questions[Questions.current_question];
- var answer = Questions.getAnswer();
- Values[question.variable] = answer;
- // FIXME: handle converting radio buttons to correct store values
- // while recording their label in the answers table
- if (answer) {
- answer = (question.answerDisplayValue && question.answerDisplayValue())
- || answer;
- Answers.appendAnswer(question.variable, question.question, answer);
- }
- Notifications.clearAlerts();
- result = true;
- } else {
- Notifications.setAlert(warnings);
- }
- return result;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Flag and result lookup
-// These messages are stored in a json file so we can also use them in the PDF
-////////////////////////////////////////////////////////////////////////////////
-
-Questions.resultMap = undefined;
-// Asynchronous fetch of data that is accessed synchronously.
-// This data won't be used until after several questions, so this is tolerable.
-
-jQuery.getJSON(jQuery("script[src*='/termination-of-transfer/js/questions.js']")
- .attr('src').replace(/questions\.js.*$/, '')
- + 'results.json')
- .done(function (result) {
- resultMap = result;
- })
- .fail(function (jqxhr, textStatus, error) {
- var err = textStatus + ", " + error;
- console.log("Request Failed: " + err);
- });
-
-Questions.getConclusionDetails = function (specifier) {
- var path = specifier.split('.');
- var result = resultMap['Conclusion'][path[0]][path[1]];
- return result;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Flow of control
-////////////////////////////////////////////////////////////////////////////////
-
-Questions.first_question = 's1q1a';
-Questions.last_question = 's2q2fii';
-
-Questions.start = function () {
- jQuery('.questionnaire-section, .question-progress-buttons')
- .removeClass('hidden');
- jQuery('.no-javascript-alert').addClass('hidden');
- //Navigation.disablePrevious();
- Rendering.transitionTo(Questions.first_question);
-};
-
-Questions.transitionQuestion = function (next_question) {
- var previous_question = Questions[Questions.current_question];
- if (previous_question) {
- if(previous_question.post) {
- previous_question.post();
- }
- }
- if (next_question == 'finish') {
- Questions.finish();
- } else {
- Questions.current_question = next_question;
- var question = Questions[Questions.current_question];
- if (question['pre']) {
- question.pre();
- }
- Rendering.transitionTo(question);
- }
-};
-
-Questions.nextQuestionID = function () {
- var next_question = Questions.current_question;
- var rule = Rules[Questions.current_question];
- if (typeof rule == 'function') {
- next_question = rule();
- } else {
- next_question = rule;
- }
- return next_question;
-};
-
-Questions.nextQuestion = function () {
- // If the answer was OK, move on
- if (Questions.processAnswer()) {
- ValuesStack.push();
- var id = Questions.nextQuestionID();
- Values.question_id = id;
- if (id == 'finish') {
- Questions.finish();
- } else {
- Questions.transitionQuestion(Values.question_id);
- // Scroll down to make sure the input UI is visible
- jQuery('html,body').animate({
- scrollTop: jQuery('#button-question-next').offset().top}, 'slow');
- }
- }
-};
-
-Questions.previousQuestion = function () {
- // If we are going back from *after* the last question, re-enable UI
- if (Values.question_id == 'finish') {
- Navigation.unfinishQuestions();
- }
- // Don't pop past the very first item
- if (ValuesStack.height() > 0) {
- // Go back
- ValuesStack.pop();
- Questions.transitionQuestion(Values.question_id);
- Notifications.clearAlerts();
- // Clear previous answer
- var previous_question = Questions[Values.question_id];
- Answers.removeAnswer(previous_question.variable);
- // Scroll down to make sure the input UI is visible
- jQuery('html,body').animate({
- scrollTop: jQuery('#button-question-next').offset().top}, 'slow');
- }
-};
-
-Questions.finish = function () {
- var obj = Questions.getConclusionDetails(Values.conclusion);
- Values.termination_type = obj.title;
- Notifications.setResultAreaMessage(obj, 'panel-success');
- Navigation.finishQuestions();
- if (Values.conclusion_generate_pdf) {
- PDF.request();
- }
-};
-
-Questions.start = function () {
- Values.reset();
- Navigation.showQuestions();
- Navigation.showAnswersTable();
- Navigation.showNextPrevious();
- jQuery('#button-question-next').click(Questions.nextQuestion);
- jQuery('#button-question-back').click(Questions.previousQuestion);
- // When the user presses "return" in a text area, move to next question
- jQuery('#question-rendering-area').on('submit', function () {
- if (jQuery('#button-question-next').is(':enabled')) {
- jQuery('#button-question-next').click();
- }
- return false;
- });
- Questions.transitionQuestion(Questions.first_question);
- Values.question_id = Questions.first_question;
-};
-
-jQuery( document ).ready(function () {
- Questions.start();
-});
diff --git a/wordpress-plugin/js/rendering.js b/wordpress-plugin/js/rendering.js
deleted file mode 100644
index 84d6159..0000000
--- a/wordpress-plugin/js/rendering.js
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- Termination of Transfer - tool to help in returning authors rights.
- Copyright (C) 2016 Creative Commons Corporation.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-////////////////////////////////////////////////////////////////////////////////
-// Rendering UI elements for input
-////////////////////////////////////////////////////////////////////////////////
-
-var Rendering = {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Sections
-////////////////////////////////////////////////////////////////////////////////
-
-Rendering.sections = [
- '',
- 'First tell us a few things about the work',
- 'Now, let’s find out whether the work is eligible for termination',
- 'Information about the work'
-];
-
-Rendering.currentSection = 0;
-
-////////////////////////////////////////////////////////////////////////////////
-// Template basics
-////////////////////////////////////////////////////////////////////////////////
-
-Rendering.questionTemplate = '\
-';
-
-Rendering.createQuestion = function () {
- return jQuery(Rendering.questionTemplate);
-};
-
-Rendering.common = function (config) {
- var question = Rendering.createQuestion();
- // If this is a question in a different section, change the section header
- // Section is 1-based, so we can use a simple logical and here.
- if (config.section
- && (config.section != Rendering.currentSection)) {
- jQuery('#section-title').html(Rendering.sections[config.section]).fadeIn();
- }
- question.find('.question-label').html(config.question);
- if (config.explanation) {
- question.find('.help-block').html(config.explanation);
- }
- question.css("display", "none");
- // If we're entering this value for the first time (not via the back button)
- // and this isn't an optional value
- // don't let the user continue until they enter a value here.
- if((Values[config.variable] === undefined)
- && (! config.optional)) {
- Navigation.disableNext();
- } else {
- Navigation.enableNext();
- }
- return question;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Multiple choice questions (radio buttons)
-////////////////////////////////////////////////////////////////////////////////
-
-Rendering.radio = function (config) {
- var question = Rendering.common(config);
- var form_group = question.find('.form-group');
- var name = 'input-' + config.variable;
- // If we are returning to this via the back button, get the previous value
- var existing_value = Values[config.variable];
- var radio_button_values = config.values || ['yes', 'no'];
- radio_button_values.forEach(function (value) {
- var radio_button = '';
- form_group.append(jQuery(radio_button));
- });
- // When the user makes a choice, go straight to the next question
- form_group.find(':input[type="radio"]').click(function () {
- Navigation.enableNext();
- jQuery('#button-question-next').click();
- });
- return question;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Text input
-////////////////////////////////////////////////////////////////////////////////
-
-Rendering.makeTextLengthHandler = function (element, min_length, optional) {
- return function () {
- var length = element.val().length;
- if ((optional && (length == 0))
- || (length >= min_length)) {
- Navigation.enableNext();
- } else {
- Navigation.disableNext();
- }
- };
-};
-
-Rendering.text = function (config) {
- var question = Rendering.common(config);
- var form_group = question.find('.form-group');
- var name = 'input-' + config.variable;
- var text_field = jQuery('');
- form_group.append(text_field);
- // Set the label
- var label = question.find('.question-label').prop('for', name);
- if (Values[config.variable]) {
- form_group.find('text-question').val(Values[config.variable]);
- }
- var existing_value = Values[config.variable];
- // Ensure next isn't enabled until enough characters are entered
- var min_length = config.min_length || 4;
- var text_field_element = question.find('.text-question');
- var validator = Rendering.makeTextLengthHandler(text_field_element,
- min_length,
- config.optional);
- text_field_element.on('keyup', validator);
- text_field_element.on('change', validator);
- // If we are returning to the field and the value has already been set, use it
- if (existing_value !== undefined) {
- text_field.val(Values[config.variable]);
- }
- return question;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Year input (text subtype)
-////////////////////////////////////////////////////////////////////////////////
-
-Rendering.year = function (config) {
- var question = Rendering.text(config);
- var text_field = question.find('.text-question');
- Validation.allowOnlyNumbers(text_field);
- text_field.prop('maxlength', 4);
- text_field.prop('placeholder', '1977');
- return question;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Render html UI from config specification
-////////////////////////////////////////////////////////////////////////////////
-
-Rendering.render = function (config) {
- var result = undefined;
- switch (config.input) {
- case 'radio':
- result = Rendering.radio(config);
- break;
- case 'year':
- result = Rendering.year(config);
- break;
- case 'text':
- // Fall through to default
- default:
- result = Rendering.text(config);
- break;
- }
- return result;
-};
-
-Rendering.transitionTo = function (config) {
- var question = Rendering.render(config);
- jQuery('.question-form').slideUp("fast",
- function () {
- jQuery(this).remove();
- });
- jQuery('#question-rendering-area').append(question);
- question.slideDown("fast");
-};
diff --git a/wordpress-plugin/js/rules.js b/wordpress-plugin/js/rules.js
deleted file mode 100644
index 3b897d3..0000000
--- a/wordpress-plugin/js/rules.js
+++ /dev/null
@@ -1,505 +0,0 @@
-/*
- Termination of Transfer - tool to help in returning authors rights.
- Copyright (C) 2016 Creative Commons Corporation.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-
-var Rules = {};
-
-Rules.simpleYesNoRule = function (variable_id, yesValue, noValue) {
- return function () {
- var result = undefined;
- if (Values[variable_id] == 'yes') {
- result = yesValue;
- } else {
- result = noValue;
- }
- return result;
- };
-};
-
-Rules.jumpToFinish = 'finish';
-
-Rules.conclusion = function (conclusion) {
- Values.conclusion = conclusion;
- return Rules.jumpToFinish;
-};
-
-Rules.conclusionPDF = function (conclusion) {
- Rules.conclusion(conclusion);
- Values.conclusion_generate_pdf = true;
- return Rules.jumpToFinish;
-};
-
-Rules.addFlag = function(flag) {
- Values.flags.push(flag);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Calculated/inferred properties
-////////////////////////////////////////////////////////////////////////////////
-
-Rules.is203 = function () {
- return (Values.conclusion == "A.iii");
-};
-
-Rules.is304 = function () {
- return (['A.i', 'A.ii', 'A.i-ii'].indexOf(Values.conclusion) > -1);
-};
-
-Rules.hasPublicDomainFlags = function () {
- var result = false;
- for (var i = 0; i < Values.flags.length; i++) {
- if (Values.flags[i][0] == 'B') {
- result = true;
- }
- }
- return result;
-};
-
-Rules.beforeEndOfNoticeWindow = function () {
- return ((Values.notice_end != undefined)
- && (Values.notice_end >= Values.current_year))
- || ((Values.d_notice_end != undefined)
- && (Values.d_notice_end >= Values.current_year))
- || ((Values.p_notice_end != undefined)
- && (Values.p_notice_end >= Values.current_year));
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Section N Analyses
-////////////////////////////////////////////////////////////////////////////////
-
-Rules.section304Analysis = function () {
- // Note that this is part of the logic from the section 203 analysis
- var result = 's1q1f';
- if (Values.k_year < 1978) {
- result = 's2q2a';
- Rules.addFlag('F.i');
- if ((Values.pub_year > 1977) && (Values.reg_year > 1977)) {
- result = Rules.conclusion('B.vii');
- } else {
- // Under the 1909 Act, copyright term begins at the earlier of
- // the registration date and the publication date.
- // If the work is both registered and published use the minimum of them.
- if ((Values.reg_year != undefined)
- && (Values.pub_year != undefined)) {
- Values.cright_year = Math.min(Values.pub_year,
- Values.reg_year);
- }
- // Otherwise use whichever value is set. One *will* be set here, see top.
- else {
- Values.cright_year = Values.reg_year || Values.pub_year;
- }
- Values.cright_year = Math.min(Values.cright_year, 1978);
- Values.term_begin = Values.cright_year + 56;
- Values.term_begin = Math.max(Values.term_begin, 1978);
- Values.term_end = Values.term_begin + 5;
- Values.notice_begin = Values.term_begin - 10;
- Values.notice_end = Values.term_end - 2;
- // If the we're presently before the 304(c) window, then we don't have to worry about 304(d)
- if (Values.notice_begin > Values.current_year) {
- Rules.addFlag('A.i.a');
- // Following Copyright Office guidance, works copyrighted before 1940 may also be eligible for termination under 304d
- } else if (Values.cright_year < 1940) {
- Rules.addFlag('F.ii');
- Values.d_term_begin = Values.term_begin + 19;
- Values.d_term_end = Values.d_term_begin + 5;
- Values.d_notice_begin = Values.d_term_begin - 10;
- Values.d_notice_end = Values.d_term_end - 2;
- if (Values.cright_year > 1936) {
- Rules.addFlag('G.i');
- }
- if (Values.cright_year == 1939) {
- Rules.addFlag('G.ii.a');
- }
- if (Values.d_notice_begin > Values.current_year) {
- // time traveler flag -- applies where the present day is between
- // the 304(c) and 304(d) notice windows
- Rules.addFlag('A.iii.a');
- } else if (Values.d_notice_end < Values.current_year) {
- Rules.addFlag('A.ii.a');
- }
- } else if (Values.notice_end < Values.current_year) {
- Rules.addFlag('A.ii.a');
- } else {
- // Here for clarity / to reflect decision tree structure
- // But note that we set it as the result above.
- result = 's2q2a';
- }
- }
- if ((Values.d_term_begin != undefined)
- && (Values.term_begin != undefined)) {
- Rules.addFlag('E.i');
- }
- }
- return result;
-};
-
-Rules.section203Analysis = function () {
- var result = 's2q2a';
- if (typeof Values.grant_pub_year !== 'undefined') {
- Rules.addFlag('F.iv');
- }
- Values.triggering_pub_year = Values.grant_pub_year || Values.pub_year;
- if (Values.k_year > 1977) {
- Rules.addFlag('F.iii');
- if (Values.pub_right == 'yes' ) {
- if (Values.triggering_pub_year != undefined) {
- Values.term_begin = Math.min(Values.triggering_pub_year + 35 ,
- Values.k_year + 40);
- } else {
- Values.term_begin = Values.k_year + 40;
- }
- } else if ((Values.triggering_pub_year != Values.k_year)
- || (Values.pub_right == 'no')) {
- Values.term_begin = Values.k_year + 35;
- }
- if (Values.term_begin != undefined) {
- Values.term_end = Values.term_begin + 5;
- Values.notice_begin = Values.term_begin - 10;
- Values.notice_end = Values.term_end - 2;
- if (Values.notice_begin > Values.current_year) {
- Rules.addFlag('A.i.a');
- } else if (Values.notice_end < Values.current_year) {
- Rules.addFlag('A.ii.a');
- }
- }
- if (Values.pub_right == 'maybe') {
- Values.p_term_begin = Values.k_year + 40;
- if (Values.triggering_pub_year != undefined) {
- Values.p_term_begin = Math.min(Values.triggering_pub_year + 35,
- Values.p_term_begin);
- }
- Values.p_term_end = Values.p_term_begin + 5;
- Values.p_notice_begin = Values.p_term_begin - 10;
- Values.p_notice_end = Values.p_term_end - 2;
- if (Values.p_notice_begin > Values.current_year) {
- Rules.addFlag('A.i.a');
- } else if (Values.p_notice_end < Values.current_year) {
- Rules.addFlag('A.ii.a');
- }
- }
- }
- if ((Values.p_term_begin != undefined)
- && (Values.term_begin != undefined)) {
- Rules.addFlag('E.ii');
- }
- return result;
-};
-
-
-////////////////////////////////////////////////////////////////////////////////
-// Section 1
-////////////////////////////////////////////////////////////////////////////////
-
-// When was the work created?
-
-Rules.s1q1a = 's1q1b';
-
-// Has the work been published?
-
-Rules.s1q1b = Rules.simpleYesNoRule('work_published',
- 's1q1bi',
- 's1q1c');
-
-// When was the work first published?
-
-Rules.s1q1bi = 's1q1bii';
-
-// When was the work first published under the grant?
-// Note that the condition is based on s1q1b, we are inserting this question
-// after 'When was the work first published?' and *then* going on to the
-// questions about registration/notices or not.
-
-Rules.s1q1bii = function () {
- var result = undefined;
- if (Values.pub_year < 1923) {
- result = Rules.conclusion('B.viii');
- } else if (Values.pub_year < 1990)
- result = 's1q1bi2';
- else {
- result = 's1q1d';
- }
- return result;
-};
-
-// Works from 1989 and earlier usually display a copyright notice...
-
-Rules.s1q1bi2 = function () {
- var result = undefined;
- if (Values.copyright_notice == 'yes') {
- result = 's1q1c';
- } else if (Values.copyright_notice == 'no') {
- // The same
- result = 's1q1c';
- if (Values.pub_year < 1989) {
- Rules.addFlag('B.i');
- } else {
- Rules.addFlag('B.ii');
- }
- } else /* maybe */ {
- result = 's1q1c';
- Rules.addFlag('B.iii');
- }
- return result;
-};
-
-// Has the work been registered with the United State Copyright Office?
-
-Rules.s1q1c = function () {
- var result = undefined;
- if (Values.work_registered == 'yes') {
- result = 's1q1ci';
- } else if (Values.work_registered == 'no') {
- result = 's1q1d';
- } else /* don't know */ {
- // If someone doesn't know, continue without asking for registration number
- result = 's1q1d';
- }
- return result;
-};
-
-// When was the work registered with the United States Copyright Office?
-
-Rules.s1q1ci = function () {
- var result = undefined;
- if (Values.reg_year < 1923) {
- result = Rules.conclusion('B.viii');
- } else {
- result = 's1q1d';
- }
- return result;
-};
-
-// For s1q1d,
-// What is the date of the agreement or transfer? ...
-
-Rules.s1q1d = function () {
- var result = undefined;
- if (Values.user_inputted_k_year != Values.k_year) {
- Rules.addFlag('H.i');
- }
- if ((Values.k_year < 1978)
- && ((Values.pub_year == undefined)
- && (Values.reg_year == undefined))) {
- result = Rules.conclusion('B.vii');
- } else {
- // Intercept the result so we can add encouragement if things look good
- result = Rules.section304Analysis();
- if ((result != Rules.jumpToFinish)
- && Rules.beforeEndOfNoticeWindow()
- && (! Rules.hasPublicDomainFlags())) {
- Notifications.setEncouragement("Both notice window and copyright status look good, let's get some more details!");
- }
- }
- return result;
-};
-
-// Did the agreement or transfer include the right of publication?
-
-Rules.s1q1f = function () {
- // Intercept the result so we can add encouragement if things look good
- var result = Rules.section203Analysis();
- if ((result != Rules.jumpToFinish)
- && Rules.beforeEndOfNoticeWindow()
- && (! Rules.hasPublicDomainFlags())) {
- Notifications.setEncouragement("Both notice window and copyright status look good, let's get some more details!");
- }
- return result;
-};
-
-
-Rules.section203Analysis;
-
-////////////////////////////////////////////////////////////////////////////////
-// Section 2
-////////////////////////////////////////////////////////////////////////////////
-
-// Is the agreement or transfer you want to terminate part of a last will...
-
-Rules.s2q2a = function () {
- var result = undefined;
- if (Values.last_will == 'yes') {
- result = Rules.conclusion('B.iv');
- } else {
- if ((Values.creation_year > 1977)
- || (((Values.pub_year == undefined) || (Values.pub_year > 1977))
- && ((Values.reg_year == undefined) || (Values.reg_year > 1977)))) {
- result = 's2q2bi';
- } else {
- result = 's2q2c';
- }
- }
- return result;
-};
-
-// Are any of the authors still alive?
-// It's i) because the conditional logic that starts b is included in a
-
-Rules.s2q2bi = function () {
- var result = undefined;
- if (Values.any_authors_alive == 'yes') {
- result = 's2q2c'
- } else {
- result = 's2q2bi2';
- }
- return result;
-};
-
-// What is the year the last surviving author died?
-
-Rules.s2q2bi2 = function () {
- var result = undefined;
- // creation_year is always set, pub_year may not be, death will be here
- if (Values.creation_year > 1977) {
- Values.pd = Values.death + 71;
- } else if ((Values.pub_year != undefined)
- && (Values.pub_year < 2003)) {
- Values.pd = Math.max((Values.death + 71), 2048);
- } else {
- Values.pd = Math.max((Values.death + 71), 2003);
- }
- // pd *will* have been set in the if/else block
- if (Values.current_year > Values.pd) {
- result = Rules.conclusion('B.viii');
- } else {
- result = 's2q2c';
- }
- return result;
-};
-
-// Was the work created within the scope of the author’s employment?
-
-Rules.s2q2c = function () {
- var result = undefined;
- if (Values.within_scope_of_employment == 'yes') {
- if (Values.creation_year > 1977) {
- result = 's2q2ci';
- } else {
- result = Rules.conclusion('B.i');
- }
- } else {
- result = 's2q2d';
- }
- return result
-};
-
-// Was there an express agreement between you...
-
-Rules.s2q2ci = function () {
- var result = undefined;
- if (Values.express_agreement == 'yes') {
- result = 's2q2d';
- } else {
- result = Rules.conclusion('B.i');
- }
- return result;
-};
-
-// Was the work created in response to a special order or commission?
-
-Rules.s2q2d = function () {
- var result = undefined;
- if (Values.special_order == 'yes') {
- if (Values.creation_year < 1978) {
- Rules.addFlag('D.i');
- result = 's2q2e';
- } else {
- result = 's2q2di';
- }
- } else {
- result = 's2q2e';
- }
- return result
-};
-
-// Was there a signed written agreement regarding the special order...
-
-Rules.s2q2di = function () {
- var result = undefined;
- if (Values.signed_written_agreement == 'yes') {
- if (Values.creation_year < 1978) {
- result = Rules.conclusion('B.iii');
- } else {
- result = 's2q2dia';
- }
- } else {
- result = 's2q2e';
- }
- return result
-};
-
-// Was the work created for use as one of the following? ...
-
-Rules.s2q2dia = function () {
- var result = undefined;
- if (Values.created_as_part_of_motion_picture == 'yes') {
- result = Rules.conclusion('C.ii');
- } else if (Values.created_as_part_of_motion_picture == 'no') {
- result = 's2q2e';
- } else /* don't know */ {
- Rules.addFlag('D.ii');
- result = 's2q2e';
- }
- return result;
-};
-
-// Has the original transfer since been renegotiated or altered?
-
-Rules.s2q2e = function () {
- var result = 's2q2f';
- if (Values.renego == 'yes') {
- Rules.addFlag('C.i');
- } else if (Values.renego == 'no') {
- // Continue
- } else /* don't know */ {
- Rules.addFlag('C.ii');
- }
- return result;
-};
-
-// Did one or more of the authors or artists enter into the agreement...
-
-Rules.s2q2f = function () {
- var result = undefined;
- if (Values.authors_entered_agreement == 'yes') {
- if (Values.k_year < 1978) {
- result = Rules.conclusionPDF('A.i-ii');
- } else /*if (k_year > 1977)*/ {
- result = Rules.conclusionPDF('A.iii');
- }
- } else {
- if (Values.k_year < 1978) {
- result = 's2q2fii';
- } else /*if (Values.k_year > 1977)*/ {
- result = Rules.conclusion('B.vi');
- }
- }
- return result;
-};
-
-// Was the agreement or transfer made by a member of...
-
-Rules.s2q2fii = function () {
- var result = undefined;
- if (Values.agreement_by_family_or_executor) {
- result = Rules.conclusionPDF('A.i-ii');
- } else {
- result = Rules.conclusion('B.v');
- }
- return result
- };
diff --git a/wordpress-plugin/js/widgets.js b/wordpress-plugin/js/widgets.js
deleted file mode 100644
index 0ff4855..0000000
--- a/wordpress-plugin/js/widgets.js
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- Termination of Transfer - tool to help in returning authors rights.
- Copyright (C) 2016 Creative Commons Corporation.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-////////////////////////////////////////////////////////////////////////////////
-// Control of the html UI
-////////////////////////////////////////////////////////////////////////////////
-
-var Widgets = {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Visual display of the user's responses
-////////////////////////////////////////////////////////////////////////////////
-
-var Answers = {};
-
-Answers.resetAnswers = function () {
- jQuery('#answers-table-rows').empty();
-};
-
-Answers.appendAnswer = function (myId, label, value) {
- if (! label) {
- label = jQuery('#' + myId + '> label').first().text();
- }
- // If the user has gone back and is changing the answer, first remove it
- Answers.removeAnswer(myId);
- jQuery('#answers-table-rows').append('
'
- + label + '
'
- + value + '
');
-};
-
-Answers.removeAnswer = function (myId) {
- jQuery('#answer-row-' + myId).remove();
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Notifications and other notices
-////////////////////////////////////////////////////////////////////////////////
-
-var Notifications = {};
-
-Notifications.clearAlerts = function () {
- jQuery('#alert-area').empty();
-};
-
-Notifications.setAlert = function (message) {
- Notifications.clearAlerts();
- jQuery('#alert-area').append('