$v) { if (property_exists($this, $k)) $this->$k = $v; else trigger_error(self::class.'::__construct - unrecognized option: ' . $k); } $this->__text = $text; if ($parent) $this->__parent = $parent; } public function getJsGlobals() : array { return $this->_parseTags(); } public function getParent() : string { return $this->__parent; } /***********************/ /* Markup tag handling */ /***********************/ private function _parseTags(array &$jsg = []) : array { return self::parseTags($this->__text, $jsg); } public static function parseTags(string $text, array &$jsg = []) : array { $jsGlobals = []; if (preg_match_all(self::DB_TAG_PATTERN, $text, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { if ($match[1] == 'statistic') $match[1] = 'achievement'; else if ($match[1] == 'icondb') $match[1] = 'icon'; // todo - respecte forced locale // match[0] => [achievement=3579 domain=ru], [spell=40120 site=fr] if ($match[1] == 'money') { if (stripos($match[0], 'items')) { if (preg_match('/items=([0-9,]+)/i', $match[0], $submatch)) { $sm = explode(',', $submatch[1]); for ($i = 0; $i < count($sm); $i+=2) $jsGlobals[Type::ITEM][$sm[$i]] = $sm[$i]; } } if (stripos($match[0], 'currency')) { if (preg_match('/currency=([0-9,]+)/i', $match[0], $submatch)) { $sm = explode(',', $submatch[1]); for ($i = 0; $i < count($sm); $i+=2) $jsGlobals[Type::CURRENCY][$sm[$i]] = $sm[$i]; } } } else if ($type = Type::getIndexFrom(Type::IDX_FILE_STR, $match[1])) $jsGlobals[$type][$match[2]] = $match[2]; } } Util::mergeJsGlobals($jsg, $jsGlobals); return $jsGlobals; } private function _stripTags(array $jsgData = []) : string { return self::stripTags($this->__text, $jsgData); } public static function stripTags(string $text, array $jsgData = []) : string { // replace DB Tags $text = preg_replace_callback(self::DB_TAG_PATTERN, function ($match) use ($jsgData) { if ($match[1] == 'statistic') $match[1] = 'achievement'; else if ($match[1] == 'icondb') $match[1] = 'icon'; else if ($match[1] == 'money') { $moneys = []; if (stripos($match[0], 'items')) { if (preg_match('/items=([0-9,]+)/i', $match[0], $submatch)) { $sm = explode(',', $submatch[1]); for ($i = 0; $i < count($sm); $i += 2) { if (!empty($jsgData[Type::ITEM][1][$sm[$i]])) $moneys[] = $jsgData[Type::ITEM][1][$sm[$i]]['name'] ?? $jsgData[Type::ITEM][1][$match[2]]['name_' . Lang::getLocale()->json()]; else $moneys[] = Util::ucFirst(Lang::game('item')).' #'.$sm[$i]; } } } if (stripos($match[0], 'currency')) { if (preg_match('/currency=([0-9,]+)/i', $match[0], $submatch)) { $sm = explode(',', $submatch[1]); for ($i = 0; $i < count($sm); $i += 2) { if (!empty($jsgData[Type::CURRENCY][1][$sm[$i]])) $moneys[] = $jsgData[Type::CURRENCY][1][$sm[$i]]['name'] ?? $jsgData[Type::CURRENCY][1][$match[2]]['name_' . Lang::getLocale()->json()]; else $moneys[] = Util::ucFirst(Lang::game('curency')).' #'.$sm[$i]; } } } return Lang::concat($moneys); } if ($type = Type::getIndexFrom(Type::IDX_FILE_STR, $match[1])) { if (!empty($jsgData[$type][1][$match[2]])) return $jsgData[$type][1][$match[2]]['name'] ?? $jsgData[$type][1][$match[2]]['name_' . Lang::getLocale()->json()]; else return Util::ucFirst(Lang::game($match[1])).' #'.$match[2]; } trigger_error('Markup::stripTags() - encountered unhandled db-tag: '.var_export($match)); return ''; }, $text); // replace line endings $text = str_replace('[br]', "\n", $text); // strip other Tags $stripped = ''; $inTag = false; for ($i = 0; $i < strlen($text); $i++) { if ($text[$i] == '[' && (!$i || $text[$i - 1] != '\\')) $inTag = true; if (!$inTag) $stripped .= $text[$i]; if ($inTag && $text[$i] == ']' && (!$i || $text[$i - 1] != '\\')) $inTag = false; } return $stripped; } /*********************/ /* String Operations */ /*********************/ public function append(string $text) : self { $this->__text .= $text; return $this; } public function prepend(string $text) : self { $this->__text = $text . $this->__text; return $this; } public function apply(\Closure $fn) : void { $this->__text = $fn($this->__text); } public function replace(string $middle, int $offset = 0, ?int $len = null) : self { // y no mb_substr_replace >:( $start = $end = ''; if ($offset < 0) $offset = mb_strlen($this->__text) + $offset; $start = mb_substr($this->__text, 0, $offset); if (!is_null($len) && $len >= 0) $end = mb_substr($this->__text, $offset + $len); else if (!is_null($len) && $len < 0) $end = mb_substr($this->__text, $offset + mb_strlen($this->__text) + $len); $this->__text = $start . $middle . $end; return $this; } private function cleanText() : string { // break script-tags, unify newlines $val = preg_replace(['/script\s*\>/i', "/\r\n/", "/\r/"], ['script>', "\n", "\n"], $this->__text); return strtr(Util::jsEscape($val), ['script>' => 'scr"+"ipt>']); } public function jsonSerialize() : array { $result = []; foreach ($this as $prop => $val) if ($val !== null && $prop[0] != '_') $result[$prop] = $val; return $result; } public function __toString() : string { if ($this->jsonSerialize()) return 'Markup.printHtml("'.$this->cleanText().'", "'.$this->__parent.'", '.Util::toJSON($this).");\n"; return 'Markup.printHtml("'.$this->cleanText().'", "'.$this->__parent."\");\n"; } } ?>