lccccccc 发表于 2023-7-24 11:18

基于Auto.js的一个HTML代码编辑器(安卓版)

本帖最后由 lccccccc 于 2023-7-26 15:26 编辑

下载:https://wwyo.lanzouk.com/b04q3ebrg
密码:52pojie 或者 52pj
说明:安装时可能会报毒,因为是Auto.js打包的,请谅解。若不放心可以自行打包

GitHub:https://github.com/lh11117/HTML_code_edit

0.1.0 代码地址:https://github.com/lh11117/HTML_code_edit/blob/c0650135bcbbe470ae4cfc1cafb2854b08a6bbdd/main.js

代码(0.1.1版,又更新了):
"ui";

importClass(android.view.KeyEvent);
importClass(android.webkit.WebView);
importClass(android.webkit.WebChromeClient);
importClass(android.webkit.WebResourceResponse);
importClass(android.webkit.WebViewClient);

importClass(android.widget.EditText);
importClass(android.text.InputType);


var info_size = 35;
var pack_size = 2;
var color = "#009688";
var running = false;
var path = "/storage/emulated/0/HTMLcodeedit/";
var htmlcode, csscode, jscode, pj; //pj: project
var not_enabled = false;
var seted1 = false,
    seted2 = false;
var storage = storages.create("html_code_edit");
ui.statusBarColor(color);

var scroll_to_where = 0;

function mainui(html, css, js, pjname) {
    ui.layout(
      <frame bg="{{color}}">
            <vertical gravity="bottom" id="info">
                <linear bg="#000000" h="{{info_size}}" id="_info">
                  <text text="" id="info_text" color="#ffffff" h="{{info_size}}" textSize="20sp" gravity="center"/>
                </linear>
            </vertical>
            <scroll margin="8 {{info_size}}" id="scroll">
                <vertical bg="#ffffff" padding="8">
                  <linear>
                        <text text="项目名称:" id="pjname_text" textSize="20sp"/>
                        <input text="pj" id="pjname" w="*" singleLine="true"/>
                  </linear>
                  <linear>
                        <text text="HTML代码区:" textSize="20sp" color="{{color}}"/>
                  </linear>
                  <linear>
                        <EditText hint="HTML" w="*" id="htmlcode" layout_width="match_parent"/>
                  </linear>
                  <linear>
                        <text text="CSS代码区:" textSize="20sp" color="{{color}}"/>
                  </linear>
                  <linear>
                        <EditText hint="CSS" w="*" id="csscode"/>
                  </linear>
                  <linear>
                        <text text="JavaScript代码区:" textSize="20sp" color="{{color}}"/>
                  </linear>
                  <linear>
                        <EditText hint="JavaScript" w="*" id="jscode"/>
                  </linear>
                </vertical>
            </scroll>
            <vertical gravity="top" margin="8 0">
                <linear bg="{{color}}" gravity="right">
                  <img text="运行代码" bg="?selectableItemBackground" h="35" tint="#ffffff" src="@drawable/ic_play_arrow_black_48dp" id="runcode"/>
                  <img text="保存代码" bg="?selectableItemBackground" h="35" tint="#ffffff" src="@drawable/ic_save_black_48dp" id="savecode"/>
                  <img text="新建代码" bg="?selectableItemBackground" h="35" tint="#ffffff" src="@drawable/ic_note_add_black_48dp" id="newcode"/>
                  <img text="打开代码" bg="?selectableItemBackground" h="35" tint="#ffffff" src="@drawable/ic_folder_open_black_48dp" id="opencode"/>
                  <img text="字体" bg="?selectableItemBackground" h="35" tint="#ffffff" src="@drawable/ic_text_fields_black_48dp" id="ttf_set"/>
                  <img text="关于" h="35" bg="?selectableItemBackground" tint="#ffffff" src="@drawable/ic_help_outline_black_48dp" id="about"/>
                </linear>
            </vertical>
            <vertical gravity="top" margin="16 0">
                <linear gravity="left">
                  <text text="HTML Code Edit" h="35" gravity="center" color="#ffffff" textSize="20sp"/>
                </linear>
            </vertical>
      </frame>
    );

    function setFont_(i) {
      var tf;
      switch (i) {
            case 0:
                tf = android.graphics.Typeface.createFromFile(java.io.File(files.path("./consolas.ttf")));
                break;
            case 1:
                tf = android.graphics.Typeface.createFromFile(java.io.File(files.path("./intel-one-mono.ttf")));
                break;
      }
      if (tf == undefined) {
            return;
      }
      ui.htmlcode.setTypeface(tf);
      ui.jscode.setTypeface(tf);
      ui.csscode.setTypeface(tf);
      fontId = i;
      storage.put("fontId", i);
    }
    ui.info.visibility = 8;
    ui.htmlcode.setText(html);
    ui.csscode.setText(css);
    ui.jscode.setText(js);
    ui.pjname.setText(pjname);
    ui.pjname.setEnabled(!not_enabled);
    pj = pjname;
    //禁用底部横线
    ui.htmlcode.setBackgroundColor(android.graphics.Color.TRANSPARENT);
    ui.csscode.setBackgroundColor(android.graphics.Color.TRANSPARENT);
    ui.jscode.setBackgroundColor(android.graphics.Color.TRANSPARENT);
    ui.pjname.setBackgroundColor(android.graphics.Color.TRANSPARENT);
    //禁用自动换行
    ui.htmlcode.setHorizontallyScrolling(true);
    ui.jscode.setHorizontallyScrolling(true);
    ui.csscode.setHorizontallyScrolling(true);
    //设置字体
    var fontId = storage.get("fontId");
    if (fontId == null) {
      fontId = 0;
    }
    setFont_(fontId);
    //添加事件
    ui.runcode.on("click", () => {
      if (isValidFolderName(ui.pjname.getText())) {
            scroll_to_where = ui.scroll.getScrollY();
            log(scroll_to_where.toString());
            running = true;
            savecode(ui);
            not_enabled = true;
            ui.pjname.setEnabled(false);
            htmlcode = ui.htmlcode.getText() + "";
            csscode = ui.csscode.getText() + "";
            jscode = ui.jscode.getText() + "";
            pj = ui.pjname.getText() + "";
            view_html(htmlcode, csscode, jscode);
            show_info("开始运行(已保存代码)");
      } else {
            alert("项目名称不合法,不能保存并运行", "目前支持大小写字母、数字,下划线和汉字")
      }
    });
    ui.savecode.on("click", () => {
      if (isValidFolderName(ui.pjname.getText())) {
            savecode(ui);
            not_enabled = true;
            ui.pjname.setEnabled(false);
            toast("文件保存成功!\n\nHTML文件已保存到" + path + ui.pjname.getText() + "/main.html\n\nCSS文件已保存到" + path + ui.pjname.getText() + "/css.css\n\nJS文件已保存到" + path + ui.pjname.getText() + "/js.js");
            if (storage.get("do_not_show_save_dialog") == true) {
                return;
            }
            dialogs.build({
                title: "养成好习惯",
                content: "勤于手动保存代码,以避免意外导致代码丢失。\n\n虽然自动保存也能为您保存代码,但遇到非正常退出(被一键加速清理掉、没电关机、程序卡死等),那就无能为力了。",
                positive: "知道了",
                checkBoxPrompt: "不再提示"
            }).on("positive", (win) => {
                win.dismiss();
            }).on("check", (checked) => {
                storage.put("do_not_show_save_dialog", checked)
            }).show();
      } else {
            alert("保存失败:项目名称不合法", "目前支持大小写字母、数字,下划线和汉字")
      }
    });
    ui.newcode.on("click", () => {
      if (!is_save()) {
            dialogs.confirm("提示", "您的代码还未保存,确定创建新的项目?", function(b) {
                if (b) {
                  new_code();
                  not_enabled = false;
                  ui.pjname.setEnabled(true);
                  show_info("创建项目成功,但没有保存到本地")
                }
            });
      } else {
            new_code();
            not_enabled = false;
            ui.pjname.setEnabled(true);
            show_info("创建项目成功,但没有保存到本地");
      }
    });
    ui.opencode.on("click", () => {
      if (!is_save()) {
            dialogs.confirm("提示", "您的代码还未保存,确定打开以前的项目?", function(b) {
                if (!b) {
                  return;
                } else {
                  open_pj();
                }
            });
      } else {
            open_pj();
      }
    });
    ui.ttf_set.click(function() {
      var ttf_list = ["Consolas", "Inter One Mono"];
      dialogs.singleChoice("更改字体", ttf_list, fontId, setFont_)
    });
    if (!seted1) {
      seted1 = true;
      ui.emitter.on("back_pressed", (event) => {
            if (running || is_save()) {
                return;
            }
            event.consumed = true;
            confirm("HTML Code Edit", "提示:您的代码还未保存,确定要退出吗?", function(b) {
                if (b) {
                  ui.finish();
                }
            });
            //savecode(ui);
            //toast("即将退出。已经保存代码。");
      });
    }
    ui.about.on("click", () => {
      alert("关于", "HTML Code Edit\n    v0.1.1 beta(测试版)\n    基于Auto.js开发\n\n因为是测试版,bug也是有的。\n遇到bug请联系开发者。");
    });
    ui.pjname_text.on("click", () => {
      if (!ui.pjname.isEnabled()) {
            alert("提示", "为了您代码的安全,以及避免HTML Code Edit读取代码文件夹出问题,所以代码一经保存,不可修改项目名称。\n\n如要修改项目名称,请在创建项目后、第一次保存代码之前进行修改。\n\n为您带来不便,请谅解!")
      }
    });
    ui.pjname.addTextChangedListener({
      onTextChanged: function(text) {
            if (!isValidFolderName(text)) {
                ui.pjname.setError("项目名称不合法");
            }
      }
    });
    ui.scroll.setScrollY(scroll_to_where);
    return text;
}


function isValidFolderName(folderName) {
    // 判断文件夹名是否为空
    if (folderName + "" === "") {
      return false;
    }

    // 定义合法文件夹名的正则表达式
    var regex = /^+$/;

    // 使用正则表达式进行匹配
    var isMatch = regex.test(folderName);

    // 返回匹配结果
    return isMatch;
}

function getpj(name) {
    let data = [];
    try {
      var p = files.join(path, name);
      var f = open(files.join(p, "data.json"), "r")
      var data = JSON.parse(f.read());
      f.close();
      var html = files.join(p, data.html);
      var css = files.join(p, data.css);
      var js = files.join(p, data.js);
      var name = data.name;
      var hc, cc, jc;
      f = open(html, "r");
      hc = f.read();
      f.close();
      f = open(css, "r");
      cc = f.read();
      f.close();
      f = open(js, "r");
      jc = f.read();
      f.close();
      data = hc;
      data = cc;
      data = jc;
      data = name;
      return data;
    } catch (err) {
      log(err);
      return null;
    }
}

function open_pj() {
    let alldir = files.listDir(path);
    let pjs = ["取消"];
    var j = 1;
    if (alldir.length == 0) {
      alert("还没有项目!请创建一个!");
      return;
    }
    for (var i = 0; i < alldir.length; i++) {
      var p = files.join(path, alldir);
      if (files.isDir(p)) {
            if (files.exists(files.join(p, "data.json"))) {
                var f = open(files.join(p, "data.json"), "r")
                try {
                  var data = JSON.parse(f.read());
                  var html = files.join(p, data.html);
                  var css = files.join(p, data.css);
                  var js = files.join(p, data.js);
                  var name = data.name;
                } catch (err) {
                  f.close();
                  log(err);
                  continue;
                }
                //log(html);
                if (files.exists(html) && files.exists(css) && files.exists(css)) {
                  pjs = name;
                  j++;
                }
            }
      }
    }
    if (pjs.length == 1) {
      alert("还没有项目!请创建一个!");
      return;
    }
    dialogs.singleChoice("打开项目", pjs).then(pjn => {
      if (pjn == 0 || pjn == -1) {
            return;
      }
      show_info("正在打开“" + pjs + "”,请稍后……");
      threads.start(function() {
            let data = getpj(pjs);
            if (data == null || pjs != data) {
                show_info("无法打开项目“" + pjs + "”,项目配置文件损坏!");
                return;
            }
            htmlcode = data;
            csscode = data;
            jscode = data;
            pj = data;
            ui.run(() => {
                ui.htmlcode.setText(htmlcode);
                ui.csscode.setText(csscode);
                ui.jscode.setText(jscode);
                ui.pjname.setText(data);
                ui.pjname.setEnabled(false);
            });
            storage.put("open_pj_name", data);
            show_info("打开“" + pjs + "”完成");
      });
    });
}

function new_code() {
    var t = new Date().getTime();
    htc = "<!--TODO:请在这里写上您的HTML代码。-->\n<!--这里提供了一些HTML的基本框架,您可以在此基础上加以修改。-->\n\n<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<title>hello</title>\n\t</head>\n\t<body>\n\t\t<p>hello</p>\n\t</body>\n</html>";
    csc = "/*TODO:请在这里写上您的CSS代码。*/\n\n";
    jsc = "/*TODO:请在这里写上您的JavaScript代码。*/\n\n";
    mainui(htc, csc, jsc, "html_project_" + t); //"HELLO_HTML_Code_Edit");
    htmlcode = htc, csscode = csc, jscode = jsc;
}

function is_save() {
    return (ui.htmlcode.getText() + "") == htmlcode && (ui.csscode.getText() + "") == csscode && (ui.jscode.getText() + "") == jscode && (ui.pjname.getText() + "") == pj;
}

function savemycode(html, css, js, name) {
    var p = path + name + "/";
    files.ensureDir(p);
    var f = open(p + "main.html", "w");
    f.write(html);
    f.close();
    f = open(p + "css.css", "w");
    f.write(css);
    f.close();
    f = open(p + "js.js", "w");
    f.write(js);
    f.close();
    f = open(p + "data.json", "w");
    data = {
      html: "main.html",
      css: "css.css",
      js: "js.js",
      name: name
    }
    f.write(JSON.stringify(data));
    f.close();
    storage.put("open_pj_name", name);
    htmlcode = html, csscode = css, jscode = js;
}

function savecode(ui) {
    try {
      savemycode(ui.htmlcode.getText() + "", ui.csscode.getText() + "", ui.jscode.getText() + "", ui.pjname.getText() + "");
    } catch (err) {
      log(err);
      savemycode(htmlcode, csscode, jscode, pj)
    }
}
//log(JSON.parse('{"hello":"6"}').hello);
//log(JSON.stringify({hello:"6"}));
function show_info(s) {
    threads.start(function() {
      ui.run(() => {
            ui.info_text.setText("" + s);
            ui.info.visibility = 0;
      });
      sleep(1000);
      ui.run(() => {
            ui.info.visibility = 8;
      });
    });
}

var htc, csc, jsc;
var open_pj_name = storage.get("open_pj_name");
if (open_pj_name == null) {
    new_code();
} else {
    var data = getpj(open_pj_name);
    if (data == null) {
      new_code();
    } else {
      mainui(data, data, data, data);
      ui.pjname.setEnabled(false);
    }
}


show_info("欢迎使用");

function view_html(h, c, j) { //h:html,c:css,j:JavaScript
    var code = "";
    //code = '<meta name="viewport" content="minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,initial-scale=1.0" /><script>document.documentElement.style.overflow=\'hidden\'; document.body.style.overflow=\'hidden\';</script><style>html{overflow-x:hidden;/* 隐藏滚动条 */}</style>';
    code = '<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">';
    //var s = code + h + '<style>' + c + '</style><script>' + j + '</script>';
    p = path + pj + "/run_temp.html";
    f = open(p, "w")
    f.writeline(code);
    f.writeline(h);
    f.writeline("<style>" + c + "</style>");
    f.writeline("<script>" + j + "</script>");
    f.close()
    runui(); //启动运行界面
    ui.run_view.loadUrl("file://" + p);
}

function runui() {
    ui.layout(
      <frame bg="{{color}}" id="f">
            <horizontal gravity="center">
                <webview id="run_view" h="*" margin="16 {{info_size}}"/>
            </horizontal>
            <vertical margin="16 {{info_size}}" layout_gravity="top" bg="#ffffff" w="*" h="*" id="ui_console_box">
                <ScrollView padding="8">
                  <text text="" id="ui_console" color="#000000" textSize="16sp"/>
                </ScrollView>
            </vertical>
            <vertical gravity="bottom" id="info">
                <linear bg="#000000" h="{{info_size}}">
                  <text text="" id="info_text" color="#ffffff" h="{{info_size}}" textSize="20sp" gravity="center"/>
                </linear>
            </vertical>
            <vertical margin="16 0">
                <linear>
                  <img text="返回" bg="?selectableItemBackground" margin="{{pack_size}} 0" id="back" tint="#ffffff" src="@drawable/ic_arrow_back_black_48dp" w="{{info_size}}" h="{{info_size}}"/>
                  <img text="刷新" bg="?selectableItemBackground" margin="{{pack_size}} 0" id="refresh" tint="#ffffff" src="@drawable/ic_replay_black_48dp" w="{{info_size}}" h="{{info_size}}"/>
                  <img text="清空" bg="?selectableItemBackground" margin="{{pack_size}} 0" id="del_all_msg" tint="#ffffff" src="@drawable/ic_delete_black_48dp" w="{{info_size}}" h="{{info_size}}"/>
                  <img text="复制" bg="?selectableItemBackground" margin="{{pack_size}} 0" id="copy_msg" tint="#ffffff" src="@drawable/ic_content_copy_black_48dp" w="{{info_size}}" h="{{info_size}}"/>
                </linear>
            </vertical>
            <vertical margin="16 0">
                <linear>
                  <text text="无标题" gravity="center" id="view_title" color="#ffffff" w="*" textSize="{{info_size-10}}sp" h="{{info_size}}"/>
                </linear>
            </vertical>
            <vertical margin="16 0">
                <linear gravity="right">
                  <img text="终端" bg="?selectableItemBackground" margin="{{pack_size}} 0" id="show_console" tint="#ffffff" src="@drawable/ic_personal_video_black_48dp" w="{{info_size}}" h="{{info_size}}"/>
                </linear>
            </vertical>
      </frame>
    );
    var console_mode = false;
    var web_title = "无标题";
    ui.info.visibility = 8;
    ui.ui_console_box.visibility = 8;
    ui.del_all_msg.visibility = 8;
    ui.copy_msg.visibility = 8;

    function show_console_func() {
      console_mode = !console_mode;
      ui.ui_console_box.visibility = 8 - ui.ui_console_box.visibility;
      ui.del_all_msg.visibility = ui.ui_console_box.visibility;
      ui.copy_msg.visibility = ui.del_all_msg.visibility;
      ui.run_view.visibility = 8 - ui.ui_console_box.visibility;
      ui.refresh.visibility = ui.run_view.visibility;
      ui.back.visibility = ui.run_view.visibility;
      if (console_mode) {
            ui.view_title.setText("终端");
            show_info("打开终端");
      } else {
            ui.view_title.setText("页面:" + web_title);
            show_info("关闭终端");
      }
    }
    var webcc = new JavaAdapter(WebChromeClient, {
      onConsoleMessage: function(consoleMessage) {
            function timestampToTime(timestamp) {
                var date = new Date(timestamp);
                var Y = date.getFullYear() + '/';
                var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '/';
                var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' ';
                var h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':';
                var m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':';
                var s = (date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()) + ".";
                var ms = date.getMilliseconds() < 100 ? ((date.getMilliseconds() < 10) ? ('00' + date.getMilliseconds()) : ('0' + date.getMilliseconds())) : date.getMilliseconds();
                return Y + M + D + h + m + s + ms;
            }
            ui.ui_console.setText(ui.ui_console.getText() + timestampToTime(Date.parse(new Date()) + ((new Date().getTime()) % 1000)) + ":" + consoleMessage.message() + "\n");
      },
      onReceivedTitle: function(view, title) {
            if (title != null) {
                web_title = title;
                if (!console_mode) {
                  ui.view_title.setText("页面:" + title);
                }
            } else {
                web_title = "无标题";
                if (!console_mode) {
                  ui.view_title.setText("无标题");
                }
            }
      },
    });
    ui.run_view.setWebChromeClient(webcc);
    ui.back.on("click", () => {
      running = false;
      mainui(htmlcode, csscode, jscode, pj);
      show_info("运行结束");
    });
    ui.refresh.on("click", () => {
      //dialogs.confirm("确认", "要刷新页面吗?", function(b) {
      //    if (b) {
      view_html(htmlcode, csscode, jscode);
      show_info("刷新页面");
      //    }
      //});
    });
    ui.del_all_msg.on("click", () => {
      ui.ui_console.setText("");
      show_info("清空终端");
    });
    ui.copy_msg.on("click", () => {
      setClip(ui.ui_console.getText() + "");
      show_info("已复制");
    });
    ui.show_console.on("click", show_console_func);
    if (!seted2) {
      seted2 = true;
      ui.emitter.on("back_pressed", (event) => {
            if (!running) {
                return;
            }
            event.consumed = true;
            if (ui.ui_console_box.visibility == 0) {
                show_console_func();
                return;
            }
            if (ui.run_view.canGoBack()) {
                ui.run_view.goBack()
                return;
            } else {
                running = false;
                mainui(htmlcode, csscode, jscode, pj);
                show_info("运行结束");
            }
      });
    }
}

软件截图:

更新说明:让编辑器变得更美观一些

软件用到的字体:



苏紫方璇 发表于 2023-7-24 12:10

本版块仅限分享编程技术和源码相关内容,发布帖子必须带上关键代码和具体功能介绍【20220924强制执行】
请在帖子中贴一下核心代码吧

mcby 发表于 2023-7-24 15:49

说实话,我个人感觉acode功能更多一点,继续加油!

追风营销 发表于 2023-7-25 21:41

从开源怎么下载不了呢 能发一下最新的吗

lccccccc 发表于 2023-7-26 08:40

追风营销 发表于 2023-7-25 21:41
从开源怎么下载不了呢 能发一下最新的吗

下载:https://wwyo.lanzouk.com/b04q3ebrg
密码:52pojie
页: [1]
查看完整版本: 基于Auto.js的一个HTML代码编辑器(安卓版)