LoginSignup
1
1

More than 5 years have passed since last update.

某掲示板投稿時にずれない用、HTMLの空白周りの挙動に対応したAAプレビューを作ってみた

Last updated at Posted at 2018-12-22

某掲示板投稿時にずれない用、HTMLの空白周りの挙動に対応したAAプレビューをWebComponents(Stencil)で作ってみる記事です。

AA投稿に影響するHTMLの空白周りの挙動って?

行頭の半角と途中の半角空白が連続すると削除される仕様です。こちらエディタでは普通に使えるため投稿するまで非常に気がつきにくいところなんです。例えば下のモナー、めっちゃ顔ずれてますよね?

Screen Shot 2018-12-23 at 1.42.11.png

でも、このズレは半角空白なので実際、掲示板に投稿しても下のように表示されます。特にずれてませんね。
Screen Shot 2018-12-23 at 1.43.03.png

今回、この挙動に対応したAAプレビューを作りました。

完成品

下のリンクをクリックしてね。
https://b.aahub.org/preview
Screen Shot 2018-12-23 at 1.46.25.png

テキストエディタ部分とプレビュー部分わけることでHTMLの空白のズレに準拠した形でAAを表示していますね。

実装内容

今回もStencilを使っています。取り回ししやすいようにIonicは使ってません。処理の内容は大きく分けて以下のとおり。

  1. textareaのinputイベントをハンドリングする
  2. inputイベントが走ったとき、textareaの内容をpreviewへinnerHtmlで描画する

以上です。

src/components/app-preview/app-preview.ts
import { Component, Element, State } from "@stencil/core";

@Component({
  tag: "app-preview",
  styleUrl: "app-preview.css"
})
export class PreviewPage {
  @State() aa: string = "";
  @Element() el: HTMLElement;

  setTextareaHeight(ta) {
    ta.style.fontSize = "12px";
    ta.style.lineHeight = "12px";
    ta.style.height = "30px";

    const minHeight = 300;
    if (ta.scrollHeight > ta.offsetHeight) {
      ta.style.height = ta.scrollHeight + "px";
    } else {
      var height, lineHeight;
      let idx = 0;
      while (true) {
        idx = idx + 1;
        height = Number(ta.style.height.split("px")[0]);
        lineHeight = Number(ta.style.lineHeight.split("px")[0]);
        ta.style.height = height - lineHeight + "px";
        if (
          ta.scrollHeight > ta.offsetHeight ||
          minHeight > ta.scrollHeight ||
          idx > 50000
        ) {
          ta.style.height = ta.scrollHeight + "px";
          break;
        }
      }
    }
  }

  getBytes(text: string = "") {
    let count = 0;
    for (let i = 0; i < text.length; i++) {
      let n = encodeURIComponent(text.charAt(i));
      if (n.length < 4) count++;
      else count += 2;
    }
    return count;
  }
  textInput(el) {
    this.setTextareaHeight(el.srcElement);
    this.aa = el.srcElement.value;

    let value = this.aa.replace(/</g, "&lt;");
    this.el.querySelector("#preview").innerHTML = value.replace(
      /\\n|\r\n|\r|\n/g,
      "<br>"
    );
  }

  componentWillLoad() {
    this.aa = "";
    let textarea: any = this.el.querySelector("#aa-textarea");
    textarea.value = "";
    this.el.querySelector("#preview").innerHTML = "";
  }

  render() {
    return [
      <div class="content-wrapper">
        <div class="u-pt20 u-pl8">{this.getBytes(this.aa)}byte</div>
        <div class="input-wrapper">
          <div class="input-aa-wrapper u-flex-wrap">
            <div class="textarea-wrapper">
              <textarea
                id="aa-textarea"
                class="input-aa"
                placeholder="アスキーアートを入力"
                onInput={e => this.textInput(e)}
              />
            </div>
            <div class="preview-wrapper">
              <div class="scroll-wrapper">
                {(() => {
                  if (this.aa == "") {
                    return (
                      <div class="u-aa">
                        プレビュー<br />行頭の半角と途中の半角2以上は除去されます
                      </div>
                    );
                  }
                })()}
                <div id="preview" />
              </div>
            </div>
          </div>
        </div>
      </div>
    ];
  }
}

CSSは長いので割愛。

ソースコード

https://github.com/AAHub/AAPreviewComponent

まとめ

以上、StencilでAAプレビューのWebComponentsを作りました。だいぶ、Stencilにも慣れてきてこれくらいのものなら10分くらいでつくれそうです(その他細かい仕様をしっているからというのもありますが)

Stencil、超おすすめなのでまだ触ったことない人はすぐさわってみてください。 
https://stenciljs.com/

それでは、

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1