diff --git a/classes/output/mobile.php b/classes/output/mobile.php
new file mode 100644
index 0000000..82325c0
--- /dev/null
+++ b/classes/output/mobile.php
@@ -0,0 +1,55 @@
+.
+
+/**
+ * Mobile output class for qtype_aitext
+ *
+ * @package qtype_aitext
+ * @copyright 2018 Marcus Green
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace qtype_aitext\output;
+
+/**
+ * Mobile output class for aitext question type
+ *
+ * @package qtype_aitext
+ * @copyright 2018 Marcus Green
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class mobile {
+
+ /**
+ * Returns the aite question type for the quiz in the mobile app.
+ * @param array $args
+ * @return array
+ */
+ public static function mobile_get_aitext($args) {
+ global $CFG;
+ $args = (object) $args;
+ $templatepath = $CFG->dirroot."/question/type/aitext/mobile/qtype_aitext.html";
+ return [
+ 'templates' => [
+ [
+ 'id' => 'main',
+ 'html' => file_get_contents($templatepath)
+ ]
+ ],
+ 'javascript' => file_get_contents($CFG->dirroot . '/question/type/aitext/mobile/mobile.js')
+ ];
+ }
+}
\ No newline at end of file
diff --git a/db/mobile.php b/db/mobile.php
new file mode 100644
index 0000000..a7c2903
--- /dev/null
+++ b/db/mobile.php
@@ -0,0 +1,53 @@
+.
+
+/**
+ * Mobile app areas for AI Text
+ *
+ * Documentation: {@link https://moodledev.io/general/app/development/plugins-development-guide}
+ *
+ * @package qtype_aitext
+ * @copyright 2024 Marcus Green
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$addons = [
+ "qtype_aitext" => [
+ "handlers" => [ // Different places where the add-on will display content.
+ 'aitext' => [ // Handler unique name (can be anything).
+ 'displaydata' => [
+ 'title' => 'AIText question',
+ 'icon' => '/question/type/aitext/pix/icon.gif',
+ 'class' => '',
+ ],
+ 'delegate' => 'CoreQuestionDelegate', // Delegate (where to display the link to the add-on).
+ 'method' => 'mobile_get_aitext',
+ 'offlinefunctions' => [
+ 'mobile_get_aitext' => [], // Function in classes/output/mobile.php.
+ ], // Function needs caching for offline.
+ 'styles' => [
+ 'url' => $CFG->wwwroot.'/question/type/aitext/mobile/qtype_aitext_app.css',
+ 'version' => '0.1'
+ ]
+ ]
+ ],
+ 'lang' => [
+ ['pluginname', 'qtype_aitext'], // Matching value in lang/en/qtype_gapfill.
+ ],
+ ]
+];
\ No newline at end of file
diff --git a/edit_aitext_form.php b/edit_aitext_form.php
index 3e04299..470305f 100755
--- a/edit_aitext_form.php
+++ b/edit_aitext_form.php
@@ -63,7 +63,7 @@ protected function definition_inner($mform) {
$mform->setType('markscheme', PARAM_RAW);
$mform->setDefault('markscheme', get_config('qtype_aitext', 'defaultmarksscheme'));
$mform->addHelpButton('markscheme', 'markscheme', 'qtype_aitext');
- if (get_config('qtype_aitext', 'markprompt_required')== 1) {
+ if (get_config('qtype_aitext', 'markprompt_required') == 1) {
$mform->addRule('markscheme', get_string('markschememissing', 'qtype_aitext'), 'required');
}
$models = explode(",", get_config('tool_aiconnect', 'model'));
diff --git a/mobile/mobile.js b/mobile/mobile.js
new file mode 100644
index 0000000..8ef5209
--- /dev/null
+++ b/mobile/mobile.js
@@ -0,0 +1,153 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see .
+
+/**
+ * PHP calls this from within
+ * classes/output/mobile.php
+ */
+/* eslint-disable no-console */
+/* eslint-env es6 */
+var that = this;
+var result = {
+ componentInit: function() {
+
+ // Check that "this.question" was provided.
+ if (! this.question) {
+ return that.CoreQuestionHelperProvider.showComponentError(that.onAbort);
+ }
+
+ // Create a temporary div to ease extraction of parts of the provided html.
+ var div = document.createElement('div');
+ div.innerHTML = this.question.html;
+
+ // Replace Moodle's correct/incorrect classes, feedback and icons with mobile versions.
+ that.CoreQuestionHelperProvider.replaceCorrectnessClasses(div);
+ that.CoreQuestionHelperProvider.replaceFeedbackClasses(div);
+ that.CoreQuestionHelperProvider.treatCorrectnessIcons(div);
+
+ // Get useful parts of the data provided in the question's html.
+ var text = div.querySelector('.qtext');
+ if (text) {
+ this.question.text = text.innerHTML;
+ }
+
+ var textarea = div.querySelector('.answer textarea');
+ if (textarea === null) {
+ // review or check
+ textarea = div.querySelector('.answer .qtype_aitext_response');
+ }
+ if (textarea) {
+ textarea.style.borderRadius = '4px';
+ textarea.style.padding = '6px 12px';
+ if (textarea.matches('.readonly')) {
+ textarea.style.border = '2px #b8dce2 solid'; // light blue
+ textarea.style.backgroundColor = '#e7f3f5'; // lighter blue
+ } else {
+ textarea.style.backgroundColor = '#edf6f7'; // lightest blue
+ }
+ this.question.textarea = textarea.outerHTML;
+ }
+
+ var itemcount = div.querySelector('.itemcount');
+ if (itemcount) {
+
+ // Replace bootstrap styles with inline styles because
+ // adding styles to 'mobile/styles_app.css' doesn't seem to be effective :-(
+ that.replaceBootstrapClasses(itemcount);
+
+ itemcount.querySelectorAll('p').forEach(function(p){
+ that.replaceBootstrapClasses(p);
+ });
+
+ // Fix background and text color on "wordswarning" span.
+ var warning = itemcount.querySelector(".warning");
+ if (warning) {
+ that.replaceBootstrapClasses(warning);
+ }
+
+ this.question.itemcount = itemcount.outerHTML;
+ }
+
+ /**
+ * questionRendered
+ */
+ this.questionRendered = function(){
+
+ var textarea = this.componentContainer.querySelector('textarea');
+ var itemcount = this.componentContainer.querySelector('.itemcount');
+ if (textarea && itemcount) {
+
+ // Maybe "this.CoreLangProvider" has a method for fetching a string
+ // but I can't find it, so we use our own method, thus:
+ var minwordswarning = that.getPluginString("qtype_aitext", "minwordswarning");
+ var maxwordswarning = that.getPluginString("qtype_aitext", "maxwordswarning");
+
+ var countitems = itemcount.querySelector(".countitems");
+ var value = countitems.querySelector(".value");
+ var warning = countitems.querySelector(".warning");
+
+ var itemtype = itemcount.dataset.itemtype;
+ var minitems = parseInt(itemcount.dataset.minitems);
+ var maxitems = parseInt(itemcount.dataset.maxitems);
+
+ var itemsplit = '';
+ switch (itemtype) {
+ case "chars": itemsplit = ""; break;
+ case "words": itemsplit = "[\\sāā]+"; break;
+ case "sentences": itemsplit = "[\\.?!]+"; break;
+ case "paragraphs": itemsplit = "[\\r\\n]+"; break;
+ }
+
+ if (itemsplit) {
+ itemsplit = new RegExp(itemsplit);
+ textarea.addEventListener("keyup", function() {
+ var text = textarea.value;
+ var warningtext = "";
+ var count = 0;
+ if (text) {
+ count = text.split(itemsplit).filter(function(item) {
+ return (item !== "");
+ }).length;
+ if (minitems && (count < minitems)) {
+ warningtext = minwordswarning;
+ }
+ if (maxitems && (count > maxitems)) {
+ warningtext = maxwordswarning;
+ }
+ }
+ value.innerText = count;
+ if (warning) {
+ warning.innerText = warningtext;
+ if (warningtext == "") {
+ warning.style.display = "none";
+ } else {
+ warning.style.display = "inline";
+ }
+ }
+ });
+ }
+ }
+ };
+
+ if (text && textarea) {
+ return true;
+ }
+
+ // Oops, the expected elements, text and textarea, were not found !!
+ return that.CoreQuestionHelperProvider.showComponentError(that.onAbort);
+ }
+};
+/* eslint-disable-next-line */
+result;
\ No newline at end of file
diff --git a/mobile/qtype_aitext.html b/mobile/qtype_aitext.html
new file mode 100644
index 0000000..1e5b44b
--- /dev/null
+++ b/mobile/qtype_aitext.html
@@ -0,0 +1,16 @@
+
\ No newline at end of file
diff --git a/mobile/qtype_aitext_app.css b/mobile/qtype_aitext_app.css
new file mode 100644
index 0000000..4c02250
--- /dev/null
+++ b/mobile/qtype_aitext_app.css
@@ -0,0 +1,9 @@
+.qtype-aitext .countwords {
+ margin-top: 0.5rem; /* mt-2 */
+ margin-bottom: 0;
+}
+.qtype-aitext .minwords,
+.qtype-aitext .minwords {
+ margin-top: 0;
+ margin-bottom: 0;
+}
\ No newline at end of file
diff --git a/version.php b/version.php
index abea491..f657268 100755
--- a/version.php
+++ b/version.php
@@ -25,10 +25,7 @@
defined('MOODLE_INTERNAL') || die();
$plugin->component = 'qtype_aitext';
-$plugin->version = 2024051109;
+$plugin->version = 2024051110;
$plugin->requires = 2020110900;
-$plugin->release = '0.01';
+$plugin->release = '0.02';
$plugin->maturity = MATURITY_BETA;
-/*$plugin->dependencies = [
- 'local_ai_manager' => ANY_VERSION,
-];*/