5단계: 웹에서 이미지 추가

이 단계에서 학습할 내용은 다음과 같습니다.

  • 앱 외부에서 리소스를 로드하고 XHR 및 ObjectURL을 통해 DOM에 추가하는 방법

이 단계를 완료하는 데 걸리는 예상 시간: 20분
이 단계에서 완료할 작업을 미리 보려면 이 페이지 하단으로 이동 ↓합니다.

CSP가 외부 리소스 사용에 미치는 영향

Chrome 앱 플랫폼은 앱이 콘텐츠 보안 정책 (CSP)을 완벽히 준수하도록 강제합니다. Chrome 앱 패키지 외부에서 이미지, 글꼴, CSS와 같은 DOM 리소스를 직접 로드할 수는 없습니다.

앱에 외부 이미지를 표시하려면 XMLHttpRequest를 통해 요청하고 Blob으로 변환한 후 ObjectURL을 만들어야 합니다. 이 ObjectURL는 앱의 컨텍스트에서 메모리 내 항목을 참조하므로 DOM에 추가할 수 있습니다.

할 일 항목의 썸네일 이미지 표시

할 일 항목에서 이미지 URL을 찾도록 앱을 변경해 보겠습니다. URL이 이미지처럼 보이는 경우 (예: .png, .jpg, .svg, .gif로 끝남) 위에 설명된 절차를 적용하여 URL 옆에 이미지 썸네일을 표시합니다.

권한 업데이트

Chrome 앱에서는 매니페스트에 도메인을 지정하는 한, 어떤 URL로든 XMLHttpRequest를 호출할 수 있습니다. 사용자가 입력할 이미지 URL을 미리 알 수 없으므로 "<all_urls>"에 요청할 권한을 요청합니다.

manifest.json에서 '' 권한을 요청합니다.

"permissions": ["storage", "alarms", "notifications",
                "webview", "<all_urls>"],

ObjectURL 만들기 및 삭제

controller.js에서 _createObjectURL() 메서드를 추가하여 Blob에서 ObjectURL을 만듭니다.

Controller.prototype._createObjectURL = function(blob) {
  var objURL = URL.createObjectURL(blob);
  this.objectURLs = this.objectURLs || [];
  this.objectURLs.push(objURL);
  return objURL;
};

ObjectURL은 메모리를 보유하므로 ObjectURL이 더 이상 필요하지 않으면 취소해야 합니다. 이를 처리하려면 이 _clearObjectURL() 메서드를 controller.js에 추가합니다.

Controller.prototype._clearObjectURL = function() {
  if (this.objectURLs) {
    this.objectURLs.forEach(function(objURL) {
      URL.revokeObjectURL(objURL);
    });
    this.objectURLs = null;
  }
};

XHR 요청

_requestRemoteImageAndAppend() 메서드를 추가하여 지정된 이미지 URL에서 XMLHttpRequest를 실행합니다.

Controller.prototype._requestRemoteImageAndAppend = function(imageUrl, element) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', imageUrl);
  xhr.responseType = 'blob';
  xhr.onload = function() {
    var img = document.createElement('img');
    img.setAttribute('data-src', imageUrl);
    img.className = 'icon';
    var objURL = this._createObjectURL(xhr.response);
    img.setAttribute('src', objURL);
    element.appendChild(img);
  }.bind(this);
  xhr.send();
};

XHR 로드 시 이 메서드는 XHR의 응답에서 ObjectURL를 만들고 이 ObjectURL를 사용하여 <img> 요소를 DOM에 추가합니다.

할 일 항목에서 이미지 URL 파싱

이제 아직 처리되지 않은 모든 링크를 찾아 이미지를 확인하는 _parseForImageURLs() 메서드를 추가합니다. 이미지처럼 보이는 각 URL에 대해 _requestRemoteImageAndAppend()를 실행합니다.

Controller.prototype._parseForImageURLs = function () {
  // remove old blobs to avoid memory leak:
  this._clearObjectURL();
  var links = this.$todoList.querySelectorAll('a[data-src]:not(.thumbnail)');
  var re = /\.(png|jpg|jpeg|svg|gif)$/;
  for (var i = 0; i<links.length; i++) {
    var url = links[i].getAttribute('data-src');
    if (re.test(url)) {
      links[i].classList.add('thumbnail');
      this._requestRemoteImageAndAppend(url, links[i]);
    }
  }
};

할 일 목록에서 썸네일 렌더링

이제 showAll(), showActive(), showCompleted()에서 _parseForImageURLs()를 호출합니다.

/**
 * An event to fire on load. Will get all items and display them in the
 * todo-list
 */
Controller.prototype.showAll = function () {
  this.model.read(function (data) {
    this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
    this._parseForImageURLs();
  }.bind(this));
};

/**
 * Renders all active tasks
 */
Controller.prototype.showActive = function () {
  this.model.read({ completed: 0 }, function (data) {
    this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
    this._parseForImageURLs();
  }.bind(this));
};

/**
 * Renders all completed tasks
 */
Controller.prototype.showCompleted = function () {
  this.model.read({ completed: 1 }, function (data) {
    this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
    this._parseForImageURLs();
  }.bind(this));
};

editItem()에서도 동일한 작업을 실행합니다.

Controller.prototype.editItem = function (id, label) {
  ...
  var onSaveHandler = function () {
    ...
    if (value.length && !discarding) {
      ...
      label.innerHTML = this._parseForURLs(value);
      this._parseForImageURLs();
    } else if (value.length === 0) {
  ...
}

표시되는 이미지 크기 제한

마지막으로 _bowercomponents/todomvc-common/base.css에 CSS 규칙을 추가하여 이미지 크기를 제한합니다.

.thumbnail img[data-src] {
  max-width: 100px;
  max-height: 28px;
}

완성된 Todo 앱을 실행합니다.

5단계를 완료했습니다. 앱을 새로고침하고 온라인으로 호스팅되는 이미지의 URL과 함께 할 일 항목을 추가합니다. 사용할 수 있는 일부 URL: http://goo.gl/nqHMF#.jpg 또는 http://goo.gl/HPBGR#.png

추가 정보

이 단계에서 도입된 일부 API에 관한 자세한 내용은 다음을 참고하세요.

다음 단계로 진행할 준비가 되셨나요? 6단계 - 파일 시스템으로 할 일 목록 내보내기 »로 이동합니다.