powered by nequal
Home » HTML_CSS_Mobile » Timeline » 1827

Changeset 1827 -- 2010-05-07 00:32:13

Comment
[Package Release] HTML_CSS_Mobile

Diffs

HTML_CSS_Mobile/tags/release-1.8.0-20100507003212/sample/sample.html

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="Shift_JIS" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml-transitional.dtd">
+<html lang="ja">
+<head>
+	<meta http-equiv="Content-Type" content="text/html;charset=Shift_JIS" />
+	<link rel="stylesheet" href="sample.css" />
+	<link rel="stylesheet" href="sample2.css" />
+	<style type="text/css">
+div.hoge {
+	color:#00FF00;
+}
+div.hoge a {
+	color:#FFFF00;
+}
+
+div.HUNI {
+  padding:30px;
+}
+	</style>
+</head>
+<body>
+<h1>test</h1>
+
+<br />
+<br/>
+<br>
+<div>hogehoge&nbsp;test</div>
+<div class="hoge">test<a href="" style="font-size:8px">test</a></div>
+<div class="HUNI">‚Ù‚°‚Ù‚°</div>
+<div>‚Ó‚ª‚Ó‚ª‡@</div>
+<a href="mailto:hoge@hogehoge?subject=hoge&amp;body=hogehoe">ƒŠƒ“ƒN</a>
+<![CDATA[cdata]]>
+<![CDATA[multi
+  line
+  cdata]]>
+<![CDATA[cdata with &nbsp; character refference]]>
+<![CDATA[CDATA with > and < ]] ]]>
+</body>
+</html>

HTML_CSS_Mobile/tags/release-1.8.0-20100507003212/sample/sample.php

@@ -0,0 +1,20 @@
+<?php
+$base_dir = dirname(__FILE__) . '/';
+require_once realpath($base_dir .'../HTML/CSS/Mobile.php'); // 開発用
+//require_once 'HTML/CSS/Mobile.php';
+
+if($argc==2) {
+  $file = $argv[1][0]=='/' ? $argv[1] : realpath($base_dir . $argv[1]);
+} else {
+  $file = realpath($base_dir.'sample.html');
+}
+
+$document = file_get_contents(realpath($base_dir.'sample.html'));
+try {
+	echo HTML_CSS_Mobile::getInstance()->setBaseDir($base_dir)->setMode('strict')->addCSSFiles(array('sample3.css', 'sample4.css'))->addCSSFiles('sample5.css')->apply($document);
+} catch (RuntimeException $e) {
+	var_dump($e);
+} catch (Exception $e) {
+	var_dump($e->getMessage());
+}
+

HTML_CSS_Mobile/tags/release-1.8.0-20100507003212/sample/nocss.html

@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title></title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  </head>
+  <body>
+    Without css.
+  </body>
+</html>

HTML_CSS_Mobile/tags/release-1.8.0-20100507003212/sample/sample.css

@@ -0,0 +1,15 @@
+body {
+	margin: 0px;
+	font-family: MSゴシック;
+}
+h1 {
+	font-size: 11px;
+}
+
+div {
+	font-size: 10px;
+}
+
+a:hover {
+	color: #0000FF;
+}

HTML_CSS_Mobile/tags/release-1.8.0-20100507003212/sample/sample2.css

@@ -0,0 +1,3 @@
+h1 {
+	color: #0000FF;
+}

HTML_CSS_Mobile/tags/release-1.8.0-20100507003212/sample/sample3.css

@@ -0,0 +1,3 @@
+div {
+	color: #FF00FF;
+}

HTML_CSS_Mobile/tags/release-1.8.0-20100507003212/sample/sample4.css

@@ -0,0 +1,3 @@
+div {
+	margin: 0px;
+}

HTML_CSS_Mobile/tags/release-1.8.0-20100507003212/sample/sample5.css

@@ -0,0 +1,3 @@
+h1 {
+	margin: 10px;
+}
属性ã«å¤‰æ›´ãŒã‚ã£ãŸãƒ‘ス: HTML_CSS_Mobile/tags/release-1.8.0-20100507003212/sample
___________________________________________________________________
åå‰: svn:externals
+

HTML_CSS_Mobile/tags/release-1.8.0-20100507003212/HTML/CSS/Mobile.php

@@ -0,0 +1,411 @@
+<?php
+/**
+ * HTML_CSS_Mobile.php
+ *
+ * @author Daichi Kamemoto <daikame@gmail.com>
+ */
+/**
+ * The MIT License
+ *
+ * Copyright (c) 2008 - 2010 Daichi Kamemoto <daikame@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+require_once 'HTML/CSS/Selector2XPath.php';
+require_once 'HTML/CSS.php';
+
+/**
+ * HTML_CSS_Mobile Mobileå‘ã‘ã«å¤–部å‚ç…§/<style>ã‚¿ã‚°ã®ã®CSSをインラインã®styleè¦ç´ ã«åŸ‹ã‚込む
+ *   Perlã®HTML::DoCoMoCSS
+ *   ( http://search.cpan.org/~tokuhirom/HTML-DoCoMoCSS-0.01/lib/HTML/DoCoMoCSS.pm )
+ *   ã®PHP移殖版
+ *
+ * @package
+ * @version 1.8
+ * @copyright 2008 - 2010 yudoufu
+ * @author Daichi Kamemoto(a.k.a yudoufu) <daikame@gmail.com>
+ * @license MIT License
+ */
+class HTML_CSS_Mobile
+{
+  private $base_dir = './';
+  private $mode = 'transit'; // mode-> transit: Exception抑制 strict: 例外発生
+  private $dom;
+  private $dom_xpath;
+  private $css_files = array();
+  private $html_css;
+  private $errors = array();
+
+  /**
+   * getInstance インスタンスをå–å¾—
+   *
+   * @return class
+   */
+  public static function getInstance()
+  {
+    return new HTML_CSS_Mobile();
+  }
+
+  /**
+   * setBaseDir CSSã®ãƒ™ãƒ¼ã‚¹ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª(通常ã¯DocumentRoot)を設定
+   *
+   * @param string $base_dir
+   * @return class
+   */
+  public function setBaseDir($base_dir)
+  {
+    $this->base_dir = $base_dir;
+    return $this;
+  }
+
+  /**
+   * setMode CSSã®ãƒã‚§ãƒƒã‚¯ãƒ¢ãƒ¼ãƒ‰ã‚’設定
+   * #TODO: ã‚‚ã£ã¨ã—ã£ã‹ã‚Šãƒ¢ãƒ¼ãƒ‰å®Ÿè£…
+   *
+   * @param string $mode
+   * @return class
+   */
+  public function setMode($mode)
+  {
+    $this->mode = $mode;
+    return $this;
+  }
+
+  /**
+   * addCSSFiles CSSã®ãƒ•ァイルをプログラムå´ã‹ã‚‰èª­ã¿è¾¼ã‚€
+   *
+   * @param array $files
+   * @return class
+   */
+  public function addCSSFiles($files)
+  {
+    foreach ((array)$files as $file)
+    {
+      if (substr($file, 0, 1) != '/')
+      {
+        $file = $this->base_dir . $file;
+      }
+
+      if (file_exists($file) && is_file($file))
+      {
+        array_push($this->css_files, $file);
+      }
+    }
+
+    return $this;
+  }
+
+  /**
+   * libxmlã®ã‚¨ãƒ©ãƒ¼ã‚’ãƒãƒ³ãƒ‰ãƒªãƒ³ã‚°ã—ãŸçµæžœã‚’è¿”ã™ã€‚
+   *   LibXMLErrorオブジェクトã®é…列ãŒè¿”ã£ã¦ãる。
+   *
+   * @return array
+   */
+  public function getXmlErrors()
+  {
+    return $this->errors;
+  }
+
+  /**
+   * apply CSSをインライン化
+   *
+   * @param  string $document 変æ›ã‚’行ã†HTML文書
+   * @param  string $base_dir CSSã®ãƒ™ãƒ¼ã‚¹ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª(setBaseDirより優先)
+   * @return string           変æ›ã•れãŸHTML
+   */
+  public function apply($document, $base_dir = '')
+  {
+    $original_document = $document;
+    /****************************************
+     * å‰å‡¦ç†
+     ****************************************/
+    if ($base_dir)
+    {
+      $this->base_dir = $base_dir;
+    }
+
+    // loadHTML/saveHTMLã®ãƒã‚°ã«å¯¾å¿œã€‚XML宣言ã®ä¸€æ™‚退é¿
+    $declaration = '';
+    if (preg_match('/^<\?xml\s[^>]+?\?>\s*/', $document, $e))
+    {
+      $declaration = $e[0];
+      $document = substr($document, strlen($declaration));
+    }
+
+    // åŒæ§˜ã«ã€<br />ãŒ<br>ã«ãªã£ã¦ã—ã¾ã†å•題ã®ãŸã‚ã«é€€é¿
+    #TODO: meta hr ç­‰ã‚‚åŒæ§˜ã ãŒã€å±é™ºãªã®ã§ã•ã‘る。。。本質的ãªè§£æ±ºã«ãªã£ã¦ã„ãªã„。
+    $document = preg_replace('/<(br\s*.*\/)>/', 'HTMLCSSBRESCAPE%$1%::::::::', $document);
+
+    // 文字å‚照をエスケープ
+    $document = preg_replace('/&(#(?:\d+|x[0-9a-fA-F]+)|[A-Za-z0-9]+);/', 'HTMLCSSINLINERESCAPE%$1%::::::::', $document);
+
+    // CDATAを退é¿
+    $cdata_pattern = '/' . preg_quote('<![CDATA[') . '.*' . preg_quote(']]>') . '/Us';
+    $escaped_cdata = null;
+    if($num_matched = preg_match_all($cdata_pattern, $document, $e))
+    {
+      $escaped_cdata = $e[0];
+      for($i = 0; $i < $num_matched; $i++)
+      {
+        $cdata_replacements[] = "HTMLCSSCDATAPLACEHOLDER$i::::::::";
+        $cdata_patterns[] = $cdata_pattern;
+      }
+      $document = preg_replace($cdata_patterns, $cdata_replacements, $document, 1);
+    }
+
+
+    // 機種ä¾å­˜æ–‡å­—ãŒã‚¨ãƒ©ãƒ¼ã«ãªã‚‹å•題を回é¿ã™ã‚‹ãŸã‚ã€UTF-8ã«å¤‰æ›ã—ã¦å‡¦ç†
+    $doc_encoding = mb_detect_encoding($document, 'sjis-win, UTF-8, eucjp-win');
+
+    switch (strtolower($doc_encoding))
+    {
+      case 'sjis-win':
+        $html_encoding = 'Shift_JIS';
+        break;
+      case 'eucjp-win':
+        $html_encoding = 'EUC-JP';
+        break;
+      default:
+        $html_encoding = '';
+        break;
+    }
+
+    if ($doc_encoding != 'UTF-8')
+    {
+      $document = str_replace(array('UTF-8', $html_encoding), array('@####UTF8####@', 'UTF-8'), $document);
+      $document = mb_convert_encoding($document, 'UTF-8', $doc_encoding);
+    }
+    /****************************************
+     * 本処ç†
+     ****************************************/
+    // libxmlã®ã‚¨ãƒ©ãƒ¼ã‚’ãƒãƒ³ãƒ‰ãƒªãƒ³ã‚°
+    libxml_use_internal_errors(true);
+
+    // XHTMLをパース
+    $this->dom = new DOMDocument();
+    $this->dom->loadHTML($document);
+
+    $this->dom_xpath = new DOMXPath($this->dom);
+
+    $this->loadCSS();
+
+    if (is_null($this->html_css))
+    {
+      return $original_document;
+    }
+
+    // CSSをインライン化
+    $css = $this->html_css->toArray();
+    $add_style = array();
+    foreach ($css as $selector => $style)
+    {
+      // ç–‘ä¼¼è¦ç´ ã¯é€€é¿ã€‚@ルールã¯ã‚¹ãƒ«ãƒ¼(Selector2XPathçš„ã«ãƒã‚°ã§ã‚„ã™ã„)
+      if (strpos($selector, '@') !== false) continue;
+      if (strpos($selector, ':') !== false)
+      {
+        $add_style[] = $selector . '{' . $this->html_css->toInline($selector) . '}';
+        continue;
+      }
+
+      $xpath = HTML_CSS_Selector2XPath::toXPath($selector);
+      $elements = $this->dom_xpath->query($xpath);
+
+      if ($elements->length == 0) continue;
+      // inlineã«ã™ã‚‹CSS文を構æˆ(toInline($selector)ã ã¨h2, h3 ãªã©ã§ã†ã¾ãã„ã‹ãªã„å•題ãŒã‚ã£ãŸãŸã‚)
+      $inline_style = '';
+      foreach ($style as $k => $v)
+      {
+        $inline_style .= $k . ':' . $v . ';';
+      }
+      foreach ($elements as $element)
+      {
+        if ($attr_style = $element->attributes->getNamedItem('style'))
+        {
+          // styleè¦ç´ ãŒå­˜åœ¨ã™ã‚‹å ´åˆã¯å‰æ–¹è¿½è¨˜
+          #TODO: ã§ãれã°ã€é‡è¤‡å›žé¿ã‚‚ã—ãŸã„。少ã—ロジックãŒã¾ã©ã‚ã£ã“ã—ã„é †åºã«ãªã£ã¦ã—ã¾ã†ã®ã ãŒã€‚。。
+          $attr_style->nodeValue = $inline_style . $attr_style->nodeValue;
+        }
+        else
+        {
+          // styleè¦ç´ ãŒå­˜åœ¨ã—ãªã„å ´åˆã¯è¿½åŠ 
+          $element->setAttribute('style', $inline_style);
+        }
+      }
+    }
+
+    // 疑似クラスを<style>ã‚¿ã‚°ã¨ã—ã¦è¿½åŠ 
+    if (!empty($add_style))
+    {
+      $new_style = implode(PHP_EOL, $add_style);
+      $new_style = str_replace(']]>', ']]]><![CDATA[]>', $new_style);
+      $new_style = implode(PHP_EOL, array('<![CDATA[', $new_style, ']]>'));
+
+      $head = $this->dom_xpath->query('//head');
+      $new_style_node = new DOMElement('style', $new_style);
+      $head->item(0)->appendChild($new_style_node)->setAttribute('type', 'text/css');
+    }
+
+    $result = $this->dom->saveHTML();
+
+
+    // libxmlã®ã‚¨ãƒ©ãƒ¼ã‚’退é¿ã—ã¦å‰Šé™¤
+    $this->errors = libxml_get_errors();
+    libxml_clear_errors();
+
+    /****************************************
+     * 後処ç†
+     ****************************************/
+
+    // æ–‡å­—ã‚³ãƒ¼ãƒ‰ã‚’å…ƒã«æˆ»ã™
+    if ($doc_encoding != 'UTF-8')
+    {
+      $result = mb_convert_encoding($result, $doc_encoding, 'UTF-8');
+      $result = str_replace(array('UTF-8', '@####UTF8####@'), array($html_encoding, 'UTF-8'), $result);
+    }
+
+    // エスケープã—ã¦ã„ãŸCDATAを復元
+    if($escaped_cdata) {
+      $result = str_replace($cdata_replacements, $escaped_cdata, $result);
+    }
+
+    // エスケープã—ã¦ã„ãŸå‚照を復元
+    $result = preg_replace('/HTMLCSSINLINERESCAPE%(#(?:\d+|x[0-9a-fA-F]+)|[A-Za-z0-9]+)%::::::::/', '&$1;', $result);
+
+    // <br />を復元
+    $result = preg_replace('/HTMLCSSBRESCAPE%(br\s*.*\/)%::::::::/', '<$1>', $result);
+
+    // 退é¿ã—ãŸXML宣言を復元
+    if (!empty($declaration))
+    {
+      $result = $declaration . $result;
+    }
+
+    return $result;
+  }
+
+  /**
+   * loadCSS 儿‰€ã§æŒ‡å®šã•れã¦ã„ã‚‹CSSファイルを読ã¿è¾¼ã¿ã€HTML_CSSã®ã‚ªãƒ–ジェクトé…列ã¨ã—ã¦æ ¼ç´ã™ã‚‹
+   *
+   * @return void
+   */
+  private function loadCSS()
+  {
+    // 外部å‚ç…§ã®CSSファイルを抽出ã™ã‚‹
+    $nodes = $this->dom_xpath->query('//link[@rel="stylesheet" or @type="text/css"] | //style[@type="text/css"]');
+
+    foreach ($nodes as $node)
+    {
+      // CSSをパース
+      #TODO: @importã®ã‚µãƒãƒ¼ãƒˆ
+      if ($node->tagName == 'link' && $href = $node->attributes->getNamedItem('href'))
+      {
+        // linkã‚¿ã‚°ã®å ´åˆ
+        if (!file_exists($this->base_dir . $href->nodeValue))
+        {
+          if ($this->mode !== 'strict') continue;
+          throw new UnexpectedValueException('ERROR: ' . $this->base_dir . $href->nodeValue . ' file does not exist');
+        }
+
+        $css_string = file_get_contents($this->base_dir . $href->nodeValue);
+      }
+      else if ($node->tagName == 'style')
+      {
+        // styleã‚¿ã‚°ã®å ´åˆ
+        $css_string = $node->nodeValue;
+      }
+
+      $this->_loadCSS($css_string);
+
+      // 読ã¿è¾¼ã¿çµ‚ã‚ã£ãŸãƒŽãƒ¼ãƒ‰ã‚’削除。親ノードãŒå–れãªã„å ´åˆã¯ã‚¹ãƒ«ãƒ¼
+      if ($parent = $node->parentNode)
+      {
+        $parent->removeChild($node);
+      }
+
+    }
+
+    // ãƒ¡ã‚½ãƒƒãƒ‰ã§æŒ‡å®šã—ãŸCSSファイルを読ã¿è¾¼ã‚€
+    if (is_array($this->css_files))
+    {
+      foreach ($this->css_files as $file)
+      {
+        $css_string = '';
+        if (substr($file, 0, 1) != '/')
+        {
+          $file = $this->base_dir . $file;
+        }
+
+        if (file_exists($file) && is_file($file))
+        {
+          $css_string = file_get_contents($file);
+          $this->_loadCSS($css_string);
+        }
+      }
+    }
+  }
+
+  /**
+   * _loadCSS
+   *
+   * @param string $css_string
+   * @return void
+   */
+  private function _loadCSS($css_string)
+  {
+    // css_stringãŒæ–‡å­—列以外
+    if (! is_string($css_string)) {
+      // strictモードãªã‚‰ã‚¨ãƒ©ãƒ¼å‡¦ç†ã€ãれ以外ã¯å‡¦ç†ã‚’スキップ
+      if ($this->mode == 'strict') {
+        throw new RuntimeException('ERROR: css content is not string');
+      }
+      return ;
+    }
+
+    // 文字コードをDOM利用ã®ãŸã‚ã«UTF-8化
+    $css_encoding = mb_detect_encoding($css_string, 'UTF-8, eucjp-win, sjis-win, iso-2022-jp');
+    if ($css_encoding != 'UTF-8')
+    {
+      $css_string = mb_convert_encoding($css_string, 'UTF-8', $css_encoding);
+    }
+
+    if (is_null($this->html_css))
+    {
+      $this->html_css = new HTML_CSS();
+    }
+
+    // CSSをクラスã¸è¿½åŠ 
+    $css_error = $this->html_css->parseString($css_string);
+    if ($this->mode == 'strict' && $css_error)
+    {
+      throw new RuntimeException('ERROR: css parse error');
+    }
+  }
+
+  /**
+   * atImportLoad
+   *
+   * @param HTML_CSS instance
+   * @return void
+   */
+  private function atImportLoad($html_css)
+  {
+    #TODO: importã®å–å¾—ãŒä¸Šæ‰‹ã出æ¥ãªã„?
+  }
+}