Re[10]: А что мешает заменить JS?
От: vdimas Россия  
Дата: 17.03.17 20:28
Оценка: 1 (1)
Здравствуйте, gandjustas, Вы писали:

V>>Тебе коллега правильно сказал — там используется функциональность браузера (АПИ DOM), а не языка JS.

V>>От JS там только динамическое выполнение кода в ячейках, но это умеют, наверно, вообще все динамические языки.
G>Накатай на любом удобном тебе языке. Уложись в 30 строк. Представь что у тебя в любом языке есть DOM API и уложись в 30 строк.

С таким форматированием? ))
Спасибо.
А если с другим форматированием в чуть большее кол-во строк на C#?
  Так пойдёт?
        void MakeExcel()
        {
            dynamic document = webBrowser1.Document.DomDocument;
            var localStorage = new Dictionary<string, string>();
            dynamic table = document.querySelector("table");

            for (var i = 0; i < 6; i++) {
                dynamic row = table.insertRow(-1);

                for (var j = 0; j < 6; j++) {
                    char letter = (char)('A' + j - 1);
                    row.insertCell(-1).innerHtml = i != 0 && j != 0
                        ? "<input id='" + letter + i + "'/>"
                        : i == 0 ? letter.ToString() : i.ToString();
                }
            }

            dynamic inputs = document.querySelectorAll("input");
            var INPUTS = new List<HtmlElement>();

            for (int i = 0, length = inputs.length; i < length; i++) {
                dynamic input = inputs[i];
                INPUTS.Add(webBrowser1.Document.GetElementById(input.id));
            }

            Func<string, object> getter = (id) => {
                if (!localStorage.ContainsKey(id))
                    return "";

                string value = localStorage[id];

                if (value.FirstOrDefault() == '=')
                    return Eval(localStorage, value.Substring(1));
                else {
                    float parsed;
                    return float.TryParse(value, out parsed) ? parsed : (object)value;
                }
            };

            Action computeAll = () => {
                foreach (var elm in INPUTS) {
                    try {
                        dynamic e = elm.DomElement;
                        e.value = getter(e.id);
                    } catch {}
                };
            };

            foreach (var elm in INPUTS) {
                elm.GotFocus += (obj, args) => {
                    dynamic e = ((HtmlElement)obj).DomElement;
                    string value;
                    if (localStorage.TryGetValue(e.id, out value))
                        e.value = value;
                    else
                        e.value = "";
                };

                elm.LostFocus += (obj, args) => {
                    dynamic e = ((HtmlElement)obj).DomElement;
                    localStorage[e.id] = e.value;
                    computeAll();
                };
            };

            computeAll();
        }


Работает...
Основные ужимки и прыжки были в том, что для доступа к DOM нужно переводить в dynamic, но при этом не получается подписаться на события, т.е. делегат не принимается.
В одном коде пришлось совместить как dynamic, так и типизированный HtmlElement сугубо для подписки на события.
Основные лишние строки именно отсюда.

И да, пытался сначала сделать на VBS в браузере, но мой IE11 говорит, что больше не поддерживает VBS.
Так шта, конкретно JS тут не при чём, он уродлив в любом случае.
А DOM мощный, это да...

  За отдельную доплату будет Eval в C#
static string Eval(Dictionary<string, string> vars, string expression)
        {
            CSharpCodeProvider c = new CSharpCodeProvider();
            ICodeCompiler icc = c.CreateCompiler();
            CompilerParameters cp = new CompilerParameters();

            cp.ReferencedAssemblies.Add("system.dll");
            cp.ReferencedAssemblies.Add("system.xml.dll");
            cp.ReferencedAssemblies.Add("system.data.dll");
            cp.ReferencedAssemblies.Add("system.windows.forms.dll");
            cp.ReferencedAssemblies.Add("system.drawing.dll");

            cp.CompilerOptions = "/t:library";
            cp.GenerateInMemory = true;

            StringBuilder sb = new StringBuilder("");
            sb.Append("using System;\n");
            sb.Append("using System.Xml;\n");
            sb.Append("using System.Data;\n");
            sb.Append("using System.Data.SqlClient;\n");
            sb.Append("using System.Windows.Forms;\n");
            sb.Append("using System.Drawing;\n");

            sb.Append("namespace CSCodeEvaler{ \n");
            sb.Append("public class CSCodeEvaler{ \n");
            sb.Append("public object EvalCode(){\n");

            foreach (var pair in vars)
            {
                float value;
                if (pair.Value == null || pair.Value.ToString() == "" ||
                    !float.TryParse(pair.Value.ToString(), out value))
                    sb.Append("float " + pair.Key + "=0;\n");
                else
                    sb.Append("float " + pair.Key + "=" + pair.Value.ToString() + ";\n");
            }

            sb.Append("return " + expression + "; \n");
            sb.Append("} \n");
            sb.Append("} \n");
            sb.Append("}\n");

            CompilerResults cr = icc.CompileAssemblyFromSource(cp, sb.ToString());

            if (cr.Errors.Count > 0)
                return "#Error";

            System.Reflection.Assembly a = cr.CompiledAssembly;
            object o = a.CreateInstance("CSCodeEvaler.CSCodeEvaler");

            Type t = o.GetType();
            MethodInfo mi = t.GetMethod("EvalCode");

            object s;
            try
            {
                s = mi.Invoke(o, null);
            }
            catch
            {
                return "#Error";
            }

            return s.ToString();
        }


  И не забыть саму HTML страницу+стили из исходного примера
<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">

<head>
    <meta charset="utf-8" />
    <title></title>
    <style>
        input {
            border: none;
            width: 80px;
            font-size: 14px;
            padding: 2px;
        }
        input:hover {
            background-color: #eee;
        }
        input:focus {
            background-color: #ccf;
        }
        input:not(:focus) {
            text-align: right;
        }
        table {
            border-collapse: collapse;
        }
        td {
            border: 1px solid #999;
            padding: 0;
        }
        tr:first-child td,
        td:first-child {
            background-color: #ccc;
            padding: 1px 3px;
            font-weight: bold;
            text-align: center;
        }
        footer {
            font-size: 80%;
        }
    </style>
</head>

<body>
    <p>Пример на C#</p>
    <table></table>
</body>

</html>


Там изначально о 30-ти строках не было и речи. ))

  Остальной код, подгружаем страницу в веб-контрол
        private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            try
            {
                MakeExcel();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            var assembly = Assembly.GetExecutingAssembly();
            var resourceName = "WindowsFormsApplication1.HTMLPage1.html";

            using (Stream stream = assembly.GetManifestResourceStream(resourceName))
            using (StreamReader reader = new StreamReader(stream))
            {
                webBrowser1.DocumentText = reader.ReadToEnd();
            }
        }
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.