r76658 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r76657‎ | r76658 | r76659 >
Date:13:44, 14 November 2010
Author:questpc
Status:deferred
Tags:
Comment:
Restored backward compatibility to MW 1.15.5. Updated XML generator.
Modified paths:
  • /trunk/extensions/WikiSync/WikiSync.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSyncBasic.php (deleted) (history)
  • /trunk/extensions/WikiSync/WikiSyncExporter.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSyncPage.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSyncQXML.php (added) (history)
  • /trunk/extensions/WikiSync/WikiSync_utils.js (modified) (history)

Diff [purge]

Index: trunk/extensions/WikiSync/WikiSyncBasic.php
@@ -1,216 +0,0 @@
2 -<?php
3 -/**
4 - * ***** BEGIN LICENSE BLOCK *****
5 - * This file is part of WikiSync.
6 - *
7 - * WikiSync is free software; you can redistribute it and/or modify
8 - * it under the terms of the GNU General Public License as published by
9 - * the Free Software Foundation; either version 2 of the License, or
10 - * (at your option) any later version.
11 - *
12 - * WikiSync is distributed in the hope that it will be useful,
13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 - * GNU General Public License for more details.
16 - *
17 - * You should have received a copy of the GNU General Public License
18 - * along with WikiSync; if not, write to the Free Software
19 - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 - *
21 - * ***** END LICENSE BLOCK *****
22 - *
23 - * WikiSync allows an AJAX-based synchronization of revisions and files between
24 - * global wiki site and it's local mirror.
25 - *
26 - * To activate this extension :
27 - * * Create a new directory named WikiSync into the directory "extensions" of MediaWiki.
28 - * * Place the files from the extension archive there.
29 - * * Add this line at the end of your LocalSettings.php file :
30 - * require_once "$IP/extensions/WikiSync/WikiSync.php";
31 - *
32 - * @version 0.3.1
33 - * @link http://www.mediawiki.org/wiki/Extension:WikiSync
34 - * @author Dmitriy Sintsov <questpc@rambler.ru>
35 - * @addtogroup Extensions
36 - */
37 -
38 -if ( !defined( 'MEDIAWIKI' ) ) {
39 - die( "This file is a part of MediaWiki extension.\n" );
40 -}
41 -
42 -/* render output data */
43 -class _QXML {
44 - // the stucture of $tag is like this:
45 - // array( "__tag"=>"td", "class"=>"myclass", 0=>"text before li", 1=>array( "__tag"=>"li", 0=>"text inside li" ), 2=>"text after li" )
46 - // both tagged and tagless lists are supported
47 - static function toText( &$tag ) {
48 - $tag_open = "";
49 - $tag_close = "";
50 - $tag_val = null;
51 - if ( is_array( $tag ) ) {
52 - ksort( $tag );
53 - if ( array_key_exists( '__tag', $tag ) ) {
54 - # list inside of tag
55 - $tag_open .= "<" . $tag[ '__tag' ];
56 - foreach ( $tag as $attr_key => &$attr_val ) {
57 - if ( is_int( $attr_key ) ) {
58 - if ( $tag_val === null )
59 - $tag_val = "";
60 - if ( is_array( $attr_val ) ) {
61 - # recursive tags
62 - $tag_val .= self::toText( $attr_val );
63 - } else {
64 - # text
65 - $tag_val .= $attr_val;
66 - }
67 - } else {
68 - # string keys are for tag attributes
69 - if ( substr( $attr_key, 0, 2 ) != "__" ) {
70 - # include only non-reserved attributes
71 - $tag_open .= " $attr_key=\"" . $attr_val . "\"";
72 - }
73 - }
74 - }
75 - if ( $tag_val !== null ) {
76 - $tag_open .= ">";
77 - $tag_close .= "</" . $tag[ '__tag' ] . ">";
78 - } else {
79 - $tag_open .= " />";
80 - }
81 - if ( array_key_exists( '__end', $tag ) ) {
82 - $tag_close .= $tag[ '__end' ];
83 - }
84 - } else {
85 - # tagless list
86 - $tag_val = "";
87 - foreach ( $tag as $attr_key => &$attr_val ) {
88 - if ( is_int( $attr_key ) ) {
89 - if ( is_array( $attr_val ) ) {
90 - # recursive tags
91 - $tag_val .= self::toText( $attr_val );
92 - } else {
93 - # text
94 - $tag_val .= $attr_val;
95 - }
96 - } else {
97 - ob_start();
98 - var_dump( $tag );
99 - $tagdump = ob_get_contents();
100 - ob_end_clean();
101 - $tag_val = "invalid argument: tagless list cannot have tag attribute values in key=$attr_key, $tagdump";
102 - }
103 - }
104 - }
105 - } else {
106 - # just a text
107 - $tag_val = $tag;
108 - }
109 - return $tag_open . $tag_val . $tag_close;
110 - }
111 -
112 - # creates one "htmlobject" row of the table
113 - # elements of $row can be either a string/number value of cell or an array( "count"=>colspannum, "attribute"=>value, 0=>html_inside_tag )
114 - # attribute maps can be like this: ("name"=>0, "count"=>colspan" )
115 - static function newRow( $row, $rowattrs = "", $celltag = "td", $attribute_maps = null ) {
116 - $result = "";
117 - if ( count( $row ) > 0 ) {
118 - foreach ( $row as &$cell ) {
119 - if ( !is_array( $cell ) ) {
120 - $cell = array( 0 => $cell );
121 - }
122 - $cell[ '__tag' ] = $celltag;
123 - $cell[ '__end' ] = "\n";
124 - if ( is_array( $attribute_maps ) ) {
125 - # converts ("count"=>3) to ("colspan"=>3) in table headers - don't use frequently
126 - foreach ( $attribute_maps as $key => $val ) {
127 - if ( array_key_exists( $key, $cell ) ) {
128 - $cell[ $val ] = $cell[ $key ];
129 - unset( $cell[ $key ] );
130 - }
131 - }
132 - }
133 - }
134 - $result = array( '__tag' => 'tr', 0 => $row, '__end' => "\n" );
135 - if ( is_array( $rowattrs ) ) {
136 - $result = array_merge( $rowattrs, $result );
137 - } elseif ( $rowattrs !== "" ) {
138 - $result[0][] = __METHOD__ . ':invalid rowattrs supplied';
139 - }
140 - }
141 - return $result;
142 - }
143 -
144 - # add row to the table
145 - static function addRow( &$table, $row, $rowattrs = "", $celltag = "td", $attribute_maps = null ) {
146 - $table[] = self::newRow( $row, $rowattrs, $celltag, $attribute_maps );
147 - }
148 -
149 - # add column to the table
150 - static function addColumn( &$table, $column, $rowattrs = "", $celltag = "td", $attribute_maps = null ) {
151 - if ( count( $column ) > 0 ) {
152 - $row = 0;
153 - foreach ( $column as &$cell ) {
154 - if ( !is_array( $cell ) ) {
155 - $cell = array( 0 => $cell );
156 - }
157 - $cell[ '__tag' ] = $celltag;
158 - $cell[ '__end' ] = "\n";
159 - if ( is_array( $attribute_maps ) ) {
160 - # converts ("count"=>3) to ("rowspan"=>3) in table headers - don't use frequently
161 - foreach ( $attribute_maps as $key => $val ) {
162 - if ( array_key_exists( $key, $cell ) ) {
163 - $cell[ $val ] = $cell[ $key ];
164 - unset( $cell[ $key ] );
165 - }
166 - }
167 - }
168 - if ( is_array( $rowattrs ) ) {
169 - $cell = array_merge( $rowattrs, $cell );
170 - } elseif ( $rowattrs !== "" ) {
171 - $cell[ 0 ] = __METHOD__ . ':invalid rowattrs supplied';
172 - }
173 - if ( !array_key_exists( $row, $table ) ) {
174 - $table[ $row ] = array( '__tag' => 'tr', '__end' => "\n" );
175 - }
176 - $table[ $row ][] = $cell;
177 - if ( array_key_exists( 'rowspan', $cell ) ) {
178 - $row += intval( $cell[ 'rowspan' ] );
179 - } else {
180 - $row++;
181 - }
182 - }
183 - $result = array( '__tag' => 'tr', 0 => $column, '__end' => "\n" );
184 - }
185 - }
186 -
187 - static function displayRow( $row, $rowattrs = "", $celltag = "td", $attribute_maps = null ) {
188 - return self::toText( self::newRow( $row, $rowattrs, $celltag, $attribute_maps ) );
189 - }
190 -
191 - // use newRow() or addColumn() to add resulting row/column to the table
192 - // if you want to use the resulting row with toText(), don't forget to apply attrs=array('__tag'=>'td')
193 - static function applyAttrsToRow( &$row, $attrs ) {
194 - if ( is_array( $attrs ) && count( $attrs > 0 ) ) {
195 - foreach ( $row as &$cell ) {
196 - if ( !is_array( $cell ) ) {
197 - $cell = array_merge( $attrs, array( $cell ) );
198 - } else {
199 - foreach ( $attrs as $attr_key => $attr_val ) {
200 - if ( !array_key_exists( $attr_key, $cell ) ) {
201 - $cell[ $attr_key ] = $attr_val;
202 - }
203 - }
204 - }
205 - }
206 - }
207 - }
208 -
209 - static function entities( $s ) {
210 - return htmlentities( $s, ENT_COMPAT, 'UTF-8' );
211 - }
212 -
213 - static function specialchars( $s ) {
214 - return htmlspecialchars( $s, ENT_COMPAT, 'UTF-8' );
215 - }
216 -
217 -} /* end of _QXML class */
Index: trunk/extensions/WikiSync/WikiSyncExporter.php
@@ -73,7 +73,7 @@
7474 class WikiSyncImportReporter extends ImportReporter {
7575 private $mResultArr = array();
7676
77 - function reportPage( $title, $origTitle, $revisionCount, $successCount ) {
 77+ function reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo = '' ) {
7878 // Add a result entry
7979 $r = array();
8080 ApiQueryBase::addTitleInfo($r, $title);
@@ -84,7 +84,7 @@
8585 # avoid bug in 1.15.4 Special:Import (new file page text without the file uploaded)
8686 # PHP Fatal error: Call to a member function insertOn() on a non-object in E:\www\psychologos\includes\specials\SpecialImport.php on line 334
8787 if ( $title->getArticleId() !== 0 ) {
88 - parent::reportPage( $title, $origTitle, $revisionCount, $successCount );
 88+ parent::reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo );
8989 }
9090 }
9191
Index: trunk/extensions/WikiSync/WikiSyncPage.php
@@ -157,7 +157,7 @@
158158 // progress explanation hint
159159 array( '__tag'=>'td', 'style'=>'font-size:9pt; ', 'colspan'=>'2', '' )
160160 ),
161 - array( '__tag'=>'tr', 'style'=>'border:1px solid gray; ',
 161+ array( '__tag'=>'tr', 'style'=>'border:1px solid gray; height:12px; ',
162162 array( '__tag'=>'td', 'style'=>'width:0%; background-color:Gold; display: none; ', '' ),
163163 array( '__tag'=>'td', 'style'=>'width:100%;', '' )
164164 )
@@ -200,7 +200,6 @@
201201 array( '__tag'=>'td', 'colspan'=>'2',
202202 // Have to explicitly set empty contents for the iframe, or we'll produce
203203 // <iframe /> which browsers consider an unclosed tag
204 - // todo: fix in _QXML class
205204 array( '__tag'=> 'iframe', 'id'=>'wikisync_iframe', 'style' => 'width:100%; height:200px; display:none; ', '' )
206205 )
207206 )
@@ -232,7 +231,8 @@
233232 WikiSyncSetup::headScripts( $wgOut, $wgContLang->isRTL() );
234233 $wgOut->setPagetitle( wfMsgHtml( 'wikisync' ) );
235234 $this->initPageTpl();
236 - $wgOut->addHTML( _QXML::toText( $this->page_tpl ) );
 235+ $wgOut->addHTML( "\n" );
 236+ $wgOut->addHTML( _QXML::toText( $this->page_tpl, 4 ) );
237237 }
238238
239239 } /* end of WikiSyncPage class */
Index: trunk/extensions/WikiSync/WikiSync.php
@@ -52,6 +52,57 @@
5353 $wgSpecialPages['WikiSync'] = array( 'WikiSyncPage' );
5454 $wgSpecialPageGroups['WikiSync'] = 'pagetools';
5555
 56+if ( !isset( $wgAutoloadClasses['FormatJson'] ) ) {
 57+ // for MediaWiki 1.15.5
 58+ class FormatJson {
 59+
 60+ /**
 61+ * Returns the JSON representation of a value.
 62+ *
 63+ * @param $value Mixed: the value being encoded. Can be any type except a resource.
 64+ * @param $isHtml Boolean
 65+ *
 66+ * @return string
 67+ */
 68+ public static function encode( $value, $isHtml = false ) {
 69+ // Some versions of PHP have a broken json_encode, see PHP bug
 70+ // 46944. Test encoding an affected character (U+20000) to
 71+ // avoid this.
 72+ if ( !function_exists( 'json_encode' ) || $isHtml || strtolower( json_encode( "\xf0\xa0\x80\x80" ) ) != '\ud840\udc00' ) {
 73+ $json = new Services_JSON();
 74+ return $json->encode( $value, $isHtml );
 75+ } else {
 76+ return json_encode( $value );
 77+ }
 78+ }
 79+
 80+ /**
 81+ * Decodes a JSON string.
 82+ *
 83+ * @param $value String: the json string being decoded.
 84+ * @param $assoc Boolean: when true, returned objects will be converted into associative arrays.
 85+ *
 86+ * @return Mixed: the value encoded in json in appropriate PHP type.
 87+ * Values true, false and null (case-insensitive) are returned as true, false
 88+ * and &null; respectively. &null; is returned if the json cannot be
 89+ * decoded or if the encoded data is deeper than the recursion limit.
 90+ */
 91+ public static function decode( $value, $assoc = false ) {
 92+ if ( !function_exists( 'json_decode' ) ) {
 93+ $json = new Services_JSON();
 94+ $jsonDec = $json->decode( $value );
 95+ if( $assoc ) {
 96+ $jsonDec = wfObjectToArray( $jsonDec );
 97+ }
 98+ return $jsonDec;
 99+ } else {
 100+ return json_decode( $value, $assoc );
 101+ }
 102+ }
 103+
 104+ }
 105+}
 106+
56107 WikiSyncSetup::init();
57108
58109 class WikiSyncSetup {
@@ -114,8 +165,11 @@
115166 self::$ScriptPath = $wgScriptPath . '/extensions' . ( ( $top_dir == 'extensions' ) ? '' : '/' . $top_dir );
116167
117168 if ( !isset( $wgAutoloadClasses['_QXML'] ) ) {
118 - $wgAutoloadClasses['_QXML'] = self::$ExtDir . '/WikiSyncBasic.php';
 169+ $wgAutoloadClasses['_QXML'] = self::$ExtDir . '/WikiSyncQXML.php';
119170 }
 171+ if ( !isset( $wgAutoloadClasses['FormatJson'] ) ) {
 172+ $wgAutoloadClasses['FormatJson'] = self::$ExtDir . '/WikiSync.php';
 173+ }
120174 $wgAutoloadClasses['Snoopy'] = self::$ExtDir . '/Snoopy/Snoopy.class.php';
121175 $wgAutoloadClasses['WikiSyncSetup'] = self::$ExtDir . '/WikiSync.php';
122176 $wgAutoloadClasses['WikiSnoopy'] =
@@ -168,7 +222,7 @@
169223 array(
170224 'scripts' => array( 'md5.js', 'WikiSync_utils.js', 'WikiSync.js' ),
171225 'styles' => 'WikiSync.css',
172 - 'messages' => array_map( 'self::setJSprefix', self::$jsMessages )
 226+ 'messages' => array_map( array( 'self', 'setJSprefix' ), self::$jsMessages )
173227 ),
174228 $localpath,
175229 $remotepath
Index: trunk/extensions/WikiSync/WikiSyncQXML.php
@@ -0,0 +1,352 @@
 2+<?php
 3+/**
 4+ * ***** BEGIN LICENSE BLOCK *****
 5+ * This file is part of WikiSync.
 6+ *
 7+ * WikiSync is free software; you can redistribute it and/or modify
 8+ * it under the terms of the GNU General Public License as published by
 9+ * the Free Software Foundation; either version 2 of the License, or
 10+ * (at your option) any later version.
 11+ *
 12+ * WikiSync is distributed in the hope that it will be useful,
 13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 15+ * GNU General Public License for more details.
 16+ *
 17+ * You should have received a copy of the GNU General Public License
 18+ * along with WikiSync; if not, write to the Free Software
 19+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 20+ *
 21+ * ***** END LICENSE BLOCK *****
 22+ *
 23+ * WikiSync allows an AJAX-based synchronization of revisions and files between
 24+ * global wiki site and it's local mirror.
 25+ *
 26+ * To activate this extension :
 27+ * * Create a new directory named WikiSync into the directory "extensions" of MediaWiki.
 28+ * * Place the files from the extension archive there.
 29+ * * Add this line at the end of your LocalSettings.php file :
 30+ * require_once "$IP/extensions/WikiSync/WikiSync.php";
 31+ *
 32+ * @version 0.3.1
 33+ * @link http://www.mediawiki.org/wiki/Extension:WikiSync
 34+ * @author Dmitriy Sintsov <questpc@rambler.ru>
 35+ * @addtogroup Extensions
 36+ */
 37+
 38+if ( !defined( 'MEDIAWIKI' ) ) {
 39+ die( "This file is a part of MediaWiki extension.\n" );
 40+}
 41+
 42+/**
 43+ * render output data v0.2
 44+ */
 45+class _QXML {
 46+
 47+ /**
 48+ * The sample stucture of $tag array is like this:
 49+ * array( '__tag'=>'td', 'class'=>'myclass', 0=>'text before li', 1=>array( '__tag'=>'li', 0=>'text inside li' ), 2=>'text after li' )
 50+ *
 51+ * '__tag' key specifies node name
 52+ * associative keys specify node attributes
 53+ * numeric keys specify inner nodes of node
 54+ *
 55+ * both tagged (with '__tag' attribute) and tagless lists are supported
 56+ *
 57+ * tagless lists cannot have associative keys (node attributes)
 58+ *
 59+ */
 60+
 61+ # next tags ignore text padding on opening (safe indent)
 62+ static $inner_indent_tags = array( 'table', 'tbody', 'tr' );
 63+ # next tags ignore text padding on closing (safe indent)
 64+ static $outer_indent_tags = array( 'table', 'tbody', 'tr', 'th', 'td', 'p' );
 65+ # next tags can be self-closed, according to
 66+ # http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
 67+ # otherwise, simple switching of Content-Type / DOCTYPE may make generated tree invalid
 68+ # see also
 69+ # http://stackoverflow.com/questions/97522/what-are-all-the-valid-self-closing-tags-in-xhtml-as-implemented-by-the-major-br
 70+ static $self_closed_tags = array( 'base', 'meta', 'link', 'hr', 'br', 'basefont', 'param', 'img', 'area', 'input', 'isindex', 'col' );
 71+
 72+ # indent types
 73+ # initial caller
 74+ const TOP_NODE = -1;
 75+ # text node
 76+ const NODE_TEXT = 0;
 77+ # tag without indentation
 78+ const NO_INDENT = 1;
 79+ # tag with outer indent
 80+ const OUTER_INDENT = 2;
 81+ # tag with inner indent
 82+ const INNER_INDENT = 3;
 83+
 84+ # used for detection of indent in non-tagged list of nodes
 85+ static $prev_indent_type;
 86+
 87+ /**
 88+ * used for erroneous $tag content reporting
 89+ */
 90+ static function getTagDump( &$tag ) {
 91+ ob_start();
 92+ var_dump( $tag );
 93+ $tagdump = ob_get_contents();
 94+ ob_end_clean();
 95+ return $tagdump;
 96+ }
 97+
 98+ /**
 99+ * recursive tags generator
 100+ * @param $tag nested associative array of tag nodes (see an example above)
 101+ * @param $indent level of indentation (negative to completely suppress indent)
 102+ */
 103+ static function toText( &$tag, $indent = -1 ) {
 104+ self::$prev_indent_type = self::TOP_NODE;
 105+ return self::_toText( $tag, $indent, self::TOP_NODE );
 106+ }
 107+
 108+ /**
 109+ * recursive tags generator
 110+ * @param $tag nested associative array of tag nodes (see an example above)
 111+ * @param $indent level of indentation (negative to completely suppress indent)
 112+ * @param $caller_indent_type indent type of lower level (caller)
 113+ */
 114+ static private function _toText( &$tag, $indent = -1, $caller_indent_type ) {
 115+ $tag_open =
 116+ $tag_close = '';
 117+ # $tag_val is a recusively concatenated inner content of tag
 118+ # by default, null value indicates a self-closing tag
 119+ $tag_val = null;
 120+ # current and nested indent levels
 121+ $nested_indent = $indent;
 122+ if ( is_array( $tag ) ) {
 123+ ksort( $tag );
 124+ $current_indent_type = self::NODE_TEXT;
 125+ if ( isset( $tag['__tag'] ) ) {
 126+ $tag_name = strtolower( $tag['__tag'] );
 127+ $current_indent_type = self::NO_INDENT;
 128+ if ( $indent >= 0 ) {
 129+ # inner has predecense (outer contains inner inside)
 130+ if ( in_array( $tag_name, self::$inner_indent_tags ) ) {
 131+ $current_indent_type = self::INNER_INDENT;
 132+ # also indent every indented tag that is inside
 133+ $nested_indent++;
 134+ } elseif ( in_array( $tag_name, self::$outer_indent_tags ) ) {
 135+ $current_indent_type = self::OUTER_INDENT;
 136+ # also indent every indented tag that is inside
 137+ $nested_indent++;
 138+ }
 139+ }
 140+ # list inside tag
 141+ $tag_open .= '<' . $tag['__tag'];
 142+ foreach ( $tag as $attr_key => &$attr_val ) {
 143+ if ( is_int( $attr_key ) ) {
 144+ # numeric node values are going into $tag_val
 145+ if ( $tag_val === null ) {
 146+ $tag_val = '';
 147+ }
 148+ if ( is_array( $attr_val ) ) {
 149+ # recursive list
 150+ $tag_val .= self::_toText( $attr_val, $nested_indent, $current_indent_type );
 151+ } else {
 152+ # text node inside tag
 153+ self::$prev_indent_type = self::NODE_TEXT;
 154+ # use the following format for the debug printouts: "!$attr_val!"
 155+ $tag_val .= $attr_val;
 156+ }
 157+ } else {
 158+ # string keys are for tag attributes
 159+ if ( substr( $attr_key, 0, 2 ) !== '__' ) {
 160+ # include only non-reserved attributes
 161+ $tag_open .= " $attr_key=\"$attr_val\"";
 162+ }
 163+ }
 164+ }
 165+ if ( $tag_val === null && !in_array( $tag_name, self::$self_closed_tags ) ) {
 166+ $tag_val = '';
 167+ }
 168+ if ( $tag_val === null ) {
 169+ $tag_open .= " />";
 170+ } else {
 171+ $tag_open .= '>';
 172+ $tag_close .= '</' . $tag['__tag'] . '>';
 173+ }
 174+ } else {
 175+ # tagless list
 176+ $tag_val = '';
 177+ foreach ( $tag as $attr_key => &$attr_val ) {
 178+ if ( is_int( $attr_key ) ) {
 179+ if ( is_array( $attr_val ) ) {
 180+ # recursive tags
 181+ $tag_val .= self::_toText( $attr_val, $indent, $caller_indent_type );
 182+ } else {
 183+ # text
 184+ if ( self::$prev_indent_type === self::INNER_INDENT ) {
 185+ $attr_val = "\n$attr_val";
 186+ }
 187+ $caller_indent_type = self::NODE_TEXT;
 188+ # use for debug printout
 189+ # $tag_val .= '~' . $attr_val . self::$prev_indent_type . '~';
 190+ $tag_val .= $attr_val;
 191+ }
 192+ } else {
 193+ $tag_val = "Invalid argument: tagless list cannot have tag attribute values in key=$attr_key, " . self::getTagDump( $tag );
 194+ }
 195+ }
 196+ return $tag_val;
 197+ }
 198+ } else {
 199+ # just a text; use "?$tag?" for debug printout
 200+ return $tag;
 201+ }
 202+ # uncomment for the debug printout
 203+ # $tag_close .= "($current_indent_type,$caller_indent_type," . self::$prev_indent_type . ")";
 204+ if ( $current_indent_type === self::INNER_INDENT ) {
 205+ $tag_open = str_repeat( "\t", $indent ) . "$tag_open\n";
 206+ $tag_close = str_repeat( "\t", $indent ) . $tag_close;
 207+ if ( in_array( $caller_indent_type, array( self::TOP_NODE, self::INNER_INDENT ) ) ) {
 208+ $tag_close = "$tag_close\n";
 209+ if ( self::$prev_indent_type === self::NODE_TEXT ) {
 210+ $tag_open = "\n$tag_open";
 211+ }
 212+ } else {
 213+ $tag_open = "\n$tag_open";
 214+ }
 215+ } elseif ( $current_indent_type === self::OUTER_INDENT ) {
 216+ if ( $caller_indent_type === self::INNER_INDENT ) {
 217+ $tag_open = str_repeat( "\t", $indent ) . $tag_open;
 218+ $tag_close = "$tag_close\n";
 219+ }
 220+ if ( self::$prev_indent_type === self::INNER_INDENT ) {
 221+ $tag_close = "\n" . str_repeat( "\t", $indent ) . $tag_close;
 222+ }
 223+ } elseif ( $current_indent_type === self::NO_INDENT ) {
 224+ if ( $indent >= 0 && $caller_indent_type === self::INNER_INDENT ) {
 225+ $tag_close .= "\n";
 226+ if ( self::$prev_indent_type === self::INNER_INDENT ) {
 227+ $tag_close = "\n$tag_close";
 228+ }
 229+ }
 230+ } elseif ( $current_indent_type === self::NODE_TEXT ) {
 231+ if ( self::$prev_indent_type === self::INNER_INDENT ) {
 232+ $tag_close = "\n$tag_close";
 233+ }
 234+ }
 235+ # we support __end only for compatibility to older versions
 236+ # it's deprecated and the usage is discouraged
 237+ if ( isset( $tag['__end'] ) ) {
 238+ $end = $tag['__end'];
 239+ if ( $end === "\n" ) {
 240+ if ( substr( $tag_close, -1 ) === "\n" ) {
 241+ $end = '';
 242+ }
 243+ }
 244+ $tag_close .= $end;
 245+ }
 246+ self::$prev_indent_type = $current_indent_type;
 247+ return $tag_open . $tag_val . $tag_close;
 248+ }
 249+
 250+ # creates one "htmlobject" row of the table
 251+ # elements of $row can be either a string/number value of cell or an array( "count"=>colspannum, "attribute"=>value, 0=>html_inside_tag )
 252+ # attribute maps can be like this: ("name"=>0, "count"=>colspan" )
 253+ static function newRow( $row, $rowattrs = "", $celltag = "td", $attribute_maps = null ) {
 254+ $result = "";
 255+ if ( count( $row ) > 0 ) {
 256+ foreach ( $row as &$cell ) {
 257+ if ( !is_array( $cell ) ) {
 258+ $cell = array( 0 => $cell );
 259+ }
 260+ $cell[ '__tag' ] = $celltag;
 261+ if ( is_array( $attribute_maps ) ) {
 262+ # converts ("count"=>3) to ("colspan"=>3) in table headers - don't use frequently
 263+ foreach ( $attribute_maps as $key => $val ) {
 264+ if ( isset( $cell[$key] ) ) {
 265+ $cell[ $val ] = $cell[ $key ];
 266+ unset( $cell[ $key ] );
 267+ }
 268+ }
 269+ }
 270+ }
 271+ $result = array( '__tag' => 'tr', 0 => $row );
 272+ if ( is_array( $rowattrs ) ) {
 273+ $result = array_merge( $rowattrs, $result );
 274+ } elseif ( $rowattrs !== "" ) {
 275+ $result[0][] = __METHOD__ . ':invalid rowattrs supplied';
 276+ }
 277+ }
 278+ return $result;
 279+ }
 280+
 281+ # add row to the table
 282+ static function addRow( &$table, $row, $rowattrs = "", $celltag = "td", $attribute_maps = null ) {
 283+ $table[] = self::newRow( $row, $rowattrs, $celltag, $attribute_maps );
 284+ }
 285+
 286+ # add column to the table
 287+ static function addColumn( &$table, $column, $rowattrs = "", $celltag = "td", $attribute_maps = null ) {
 288+ if ( count( $column ) > 0 ) {
 289+ $row = 0;
 290+ foreach ( $column as &$cell ) {
 291+ if ( !is_array( $cell ) ) {
 292+ $cell = array( 0 => $cell );
 293+ }
 294+ $cell[ '__tag' ] = $celltag;
 295+ if ( is_array( $attribute_maps ) ) {
 296+ # converts ("count"=>3) to ("rowspan"=>3) in table headers - don't use frequently
 297+ foreach ( $attribute_maps as $key => $val ) {
 298+ if ( isset( $cell[$key] ) ) {
 299+ $cell[ $val ] = $cell[ $key ];
 300+ unset( $cell[ $key ] );
 301+ }
 302+ }
 303+ }
 304+ if ( is_array( $rowattrs ) ) {
 305+ $cell = array_merge( $rowattrs, $cell );
 306+ } elseif ( $rowattrs !== "" ) {
 307+ $cell[ 0 ] = __METHOD__ . ':invalid rowattrs supplied';
 308+ }
 309+ if ( !isset( $table[$row] ) ) {
 310+ $table[ $row ] = array( '__tag' => 'tr' );
 311+ }
 312+ $table[ $row ][] = $cell;
 313+ if ( isset( $cell['rowspan'] ) ) {
 314+ $row += intval( $cell[ 'rowspan' ] );
 315+ } else {
 316+ $row++;
 317+ }
 318+ }
 319+ $result = array( '__tag' => 'tr', 0 => $column );
 320+ }
 321+ }
 322+
 323+ static function displayRow( $row, $rowattrs = "", $celltag = "td", $attribute_maps = null ) {
 324+ return self::toText( self::newRow( $row, $rowattrs, $celltag, $attribute_maps ) );
 325+ }
 326+
 327+ // use newRow() or addColumn() to add resulting row/column to the table
 328+ // if you want to use the resulting row with toText(), don't forget to apply attrs=array('__tag'=>'td')
 329+ static function applyAttrsToRow( &$row, $attrs ) {
 330+ if ( is_array( $attrs ) && count( $attrs > 0 ) ) {
 331+ foreach ( $row as &$cell ) {
 332+ if ( !is_array( $cell ) ) {
 333+ $cell = array_merge( $attrs, array( $cell ) );
 334+ } else {
 335+ foreach ( $attrs as $attr_key => $attr_val ) {
 336+ if ( !isset( $cell[$attr_key] ) ) {
 337+ $cell[ $attr_key ] = $attr_val;
 338+ }
 339+ }
 340+ }
 341+ }
 342+ }
 343+ }
 344+
 345+ static function entities( $s ) {
 346+ return htmlentities( $s, ENT_COMPAT, 'UTF-8' );
 347+ }
 348+
 349+ static function specialchars( $s ) {
 350+ return htmlspecialchars( $s, ENT_COMPAT, 'UTF-8' );
 351+ }
 352+
 353+} /* end of _QXML class */
Property changes on: trunk/extensions/WikiSync/WikiSyncQXML.php
___________________________________________________________________
Added: svn:eol-style
1354 + native
Index: trunk/extensions/WikiSync/WikiSync_utils.js
@@ -132,13 +132,15 @@
133133 */
134134 window.WikiSyncPercentsIndicator = function( id ) {
135135 this.topElement = document.getElementById( id );
136 - var tr1 = this.topElement.firstChild.firstChild;
 136+ // cannot use .firstChild here, because in FF indentation text nodes are inserted
 137+ // between TABLE / TR / TD
 138+ // (in IE8 the indentation is ignored and .firstChild worked)
 139+ var elements = this.topElement.getElementsByTagName( 'TD' );
137140 // description line will be stored there
138 - this.descriptionContainer = tr1.firstChild;
139 - var tr2 = tr1.nextSibling;
 141+ this.descriptionContainer = elements[0];
140142 // td1 and td2 are used together as percent indicators
141 - this.td1 = tr2.firstChild;
142 - this.td2 = this.td1.nextSibling;
 143+ this.td1 = elements[1];
 144+ this.td2 = elements[2];
143145 this.reset();
144146 }
145147

Status & tagging log