r95728 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r95727‎ | r95728 | r95729 >
Date:23:36, 29 August 2011
Author:krinkle
Status:ok
Tags:
Comment:
Make file names match module names.
* See [[Coding conventions#File naming]]
* This pretty much undos r94325.
Modified paths:
  • /trunk/phase3/resources/Resources.php (modified) (history)
  • /trunk/phase3/resources/mediawiki/mediawiki.Title.js (added) (history)
  • /trunk/phase3/resources/mediawiki/mediawiki.Uri.js (added) (history)
  • /trunk/phase3/resources/mediawiki/mediawiki.title.js (deleted) (history)
  • /trunk/phase3/resources/mediawiki/mediawiki.uri.js (deleted) (history)
  • /trunk/phase3/tests/jasmine/SpecRunner.html (modified) (history)
  • /trunk/phase3/tests/jasmine/spec/mediawiki.Uri.spec.js (added) (history)
  • /trunk/phase3/tests/jasmine/spec/mediawiki.uri.spec.js (deleted) (history)
  • /trunk/phase3/tests/qunit/index.html (modified) (history)
  • /trunk/phase3/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js (added) (history)
  • /trunk/phase3/tests/qunit/suites/resources/mediawiki/mediawiki.title.test.js (deleted) (history)

Diff [purge]

Index: trunk/phase3/tests/qunit/index.html
@@ -68,7 +68,7 @@
6969 <script src="../../resources/jquery/jquery.tabIndex.js"></script>
7070 <script src="../../resources/jquery/jquery.tablesorter.js"></script>
7171 <script src="../../resources/jquery/jquery.textSelection.js"></script>
72 - <script src="../../resources/mediawiki/mediawiki.title.js"></script>
 72+ <script src="../../resources/mediawiki/mediawiki.Title.js"></script>
7373 <script src="../../resources/mediawiki.special/mediawiki.special.js"></script>
7474 <script src="../../resources/mediawiki.special/mediawiki.special.recentchanges.js"></script>
7575
@@ -96,7 +96,7 @@
9797 <script src="suites/resources/jquery/jquery.tabIndex.test.js"></script>
9898 <script src="suites/resources/jquery/jquery.tablesorter.test.js" charset="UTF-8"></script>
9999 <script src="suites/resources/jquery/jquery.textSelection.test.js" charset="UTF-8"></script>
100 - <script src="suites/resources/mediawiki/mediawiki.title.test.js"></script>
 100+ <script src="suites/resources/mediawiki/mediawiki.Title.test.js"></script>
101101 <script src="suites/resources/mediawiki.special/mediawiki.special.recentchanges.test.js"></script>
102102 </head>
103103 <body>
Index: trunk/phase3/tests/qunit/suites/resources/mediawiki/mediawiki.title.test.js
@@ -1,195 +0,0 @@
2 -module( 'mediawiki.title' );
3 -
4 -// mw.Title relies on these three config vars
5 -// Restore them after each test run
6 -var _titleConfig = function() {
7 -
8 - mw.config.set({
9 - "wgFormattedNamespaces": {
10 - "-2": "Media",
11 - "-1": "Special",
12 - "0": "",
13 - "1": "Talk",
14 - "2": "User",
15 - "3": "User talk",
16 - "4": "Wikipedia",
17 - "5": "Wikipedia talk",
18 - "6": "File",
19 - "7": "File talk",
20 - "8": "MediaWiki",
21 - "9": "MediaWiki talk",
22 - "10": "Template",
23 - "11": "Template talk",
24 - "12": "Help",
25 - "13": "Help talk",
26 - "14": "Category",
27 - "15": "Category talk",
28 - /* testing custom / localized */
29 - "100": "Penguins"
30 - },
31 - "wgNamespaceIds": {
32 - "media": -2,
33 - "special": -1,
34 - "": 0,
35 - "talk": 1,
36 - "user": 2,
37 - "user_talk": 3,
38 - "wikipedia": 4,
39 - "wikipedia_talk": 5,
40 - "file": 6,
41 - "file_talk": 7,
42 - "mediawiki": 8,
43 - "mediawiki_talk": 9,
44 - "template": 10,
45 - "template_talk": 11,
46 - "help": 12,
47 - "help_talk": 13,
48 - "category": 14,
49 - "category_talk": 15,
50 - "image": 6,
51 - "image_talk": 7,
52 - "project": 4,
53 - "project_talk": 5,
54 - /* testing custom / alias */
55 - "penguins": 100,
56 - "antarctic_waterfowl": 100
57 - },
58 - "wgCaseSensitiveNamespaces": []
59 - });
60 -};
61 -
62 -test( '-- Initial check', function() {
63 - expect(1);
64 - ok( mw.Title, 'mw.Title defined' );
65 -});
66 -
67 -test( 'Transform between Text and Db', function() {
68 - expect(2);
69 - _titleConfig();
70 -
71 - var title;
72 -
73 - title = new mw.Title( 'File:quux pif.jpg' );
74 - equal( title.getName(), 'Quux_pif' );
75 -
76 - title = new mw.Title( 'File:Glarg_foo_glang.jpg' );
77 - equal( title.getNameText(), 'Glarg foo glang' );
78 -});
79 -
80 -test( 'Main text for filename', function() {
81 - expect(8);
82 - _titleConfig();
83 -
84 - var title = new mw.Title( 'File:foo_bar.JPG' );
85 -
86 - equal( title.getNamespaceId(), 6 );
87 - equal( title.getNamespacePrefix(), 'File:' );
88 - equal( title.getName(), 'Foo_bar' );
89 - equal( title.getNameText(), 'Foo bar' );
90 - equal( title.getMain(), 'Foo_bar.jpg' );
91 - equal( title.getMainText(), 'Foo bar.jpg' );
92 - equal( title.getExtension(), 'jpg' );
93 - equal( title.getDotExtension(), '.jpg' );
94 -});
95 -
96 -test( 'Namespace detection and conversion', function() {
97 - expect(6);
98 - _titleConfig();
99 -
100 - var title;
101 -
102 - title = new mw.Title( 'something.PDF', 6 );
103 - equal( title.toString(), 'File:Something.pdf' );
104 -
105 - title = new mw.Title( 'NeilK', 3 );
106 - equal( title.toString(), 'User_talk:NeilK' );
107 - equal( title.toText(), 'User talk:NeilK' );
108 -
109 - title = new mw.Title( 'Frobisher', 100 );
110 - equal( title.toString(), 'Penguins:Frobisher' );
111 -
112 - title = new mw.Title( 'antarctic_waterfowl:flightless_yet_cute.jpg' );
113 - equal( title.toString(), 'Penguins:Flightless_yet_cute.jpg' );
114 -
115 - title = new mw.Title( 'Penguins:flightless_yet_cute.jpg' );
116 - equal( title.toString(), 'Penguins:Flightless_yet_cute.jpg' );
117 -});
118 -
119 -test( 'Throw error on invalid title', function() {
120 - expect(1);
121 - _titleConfig();
122 -
123 - raises(function() {
124 - var title = new mw.Title( '' );
125 - }, 'Throw error on empty string' );
126 -});
127 -
128 -test( 'Case-sensivity', function() {
129 - expect(3);
130 - _titleConfig();
131 -
132 - var title;
133 -
134 - // Default config
135 - mw.config.set( 'wgCaseSensitiveNamespaces', [] );
136 -
137 - title = new mw.Title( 'article' );
138 - equal( title.toString(), 'Article', 'Default config: No sensitive namespaces by default. First-letter becomes uppercase' );
139 -
140 - // $wgCapitalLinks = false;
141 - mw.config.set( 'wgCaseSensitiveNamespaces', [0, -2, 1, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15] );
142 -
143 - title = new mw.Title( 'article' );
144 - equal( title.toString(), 'article', '$wgCapitalLinks=false: Article namespace is sensitive, first-letter case stays lowercase' );
145 -
146 - title = new mw.Title( 'john', 2 );
147 - equal( title.toString(), 'User:John', '$wgCapitalLinks=false: User namespace is insensitive, first-letter becomes uppercase' );
148 -});
149 -
150 -test( 'toString / toText', function() {
151 - expect(2);
152 - _titleConfig();
153 -
154 - var title = new mw.Title( 'Some random page' );
155 -
156 - equal( title.toString(), title.getPrefixedDb() );
157 - equal( title.toText(), title.getPrefixedText() );
158 -});
159 -
160 -test( 'Exists', function() {
161 - expect(3);
162 - _titleConfig();
163 -
164 - var title;
165 -
166 - // Empty registry, checks default to null
167 -
168 - title = new mw.Title( 'Some random page', 4 );
169 - strictEqual( title.exists(), null, 'Return null with empty existance registry' );
170 -
171 - // Basic registry, checks default to boolean
172 - mw.Title.exist.set( ['Does_exist', 'User_talk:NeilK', 'Wikipedia:Sandbox_rules'], true );
173 - mw.Title.exist.set( ['Does_not_exist', 'User:John', 'Foobar'], false );
174 -
175 - title = new mw.Title( 'Project:Sandbox rules' );
176 - assertTrue( title.exists(), 'Return true for page titles marked as existing' );
177 - title = new mw.Title( 'Foobar' );
178 - assertFalse( title.exists(), 'Return false for page titles marked as inexisting' );
179 -
180 -});
181 -
182 -test( 'Url', function() {
183 - expect(2);
184 - _titleConfig();
185 -
186 - var title;
187 -
188 - // Config
189 - mw.config.set( 'wgArticlePath', '/wiki/$1' );
190 -
191 - title = new mw.Title( 'Foobar' );
192 - equal( title.getUrl(), '/wiki/Foobar', 'Basic functionally, toString passing to wikiGetlink' );
193 -
194 - title = new mw.Title( 'John Doe', 3 );
195 - equal( title.getUrl(), '/wiki/User_talk:John_Doe', 'Escaping in title and namespace for urls' );
196 -});
\ No newline at end of file
Index: trunk/phase3/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js
@@ -0,0 +1,195 @@
 2+module( 'mediawiki.Title' );
 3+
 4+// mw.Title relies on these three config vars
 5+// Restore them after each test run
 6+var _titleConfig = function() {
 7+
 8+ mw.config.set({
 9+ "wgFormattedNamespaces": {
 10+ "-2": "Media",
 11+ "-1": "Special",
 12+ "0": "",
 13+ "1": "Talk",
 14+ "2": "User",
 15+ "3": "User talk",
 16+ "4": "Wikipedia",
 17+ "5": "Wikipedia talk",
 18+ "6": "File",
 19+ "7": "File talk",
 20+ "8": "MediaWiki",
 21+ "9": "MediaWiki talk",
 22+ "10": "Template",
 23+ "11": "Template talk",
 24+ "12": "Help",
 25+ "13": "Help talk",
 26+ "14": "Category",
 27+ "15": "Category talk",
 28+ /* testing custom / localized */
 29+ "100": "Penguins"
 30+ },
 31+ "wgNamespaceIds": {
 32+ "media": -2,
 33+ "special": -1,
 34+ "": 0,
 35+ "talk": 1,
 36+ "user": 2,
 37+ "user_talk": 3,
 38+ "wikipedia": 4,
 39+ "wikipedia_talk": 5,
 40+ "file": 6,
 41+ "file_talk": 7,
 42+ "mediawiki": 8,
 43+ "mediawiki_talk": 9,
 44+ "template": 10,
 45+ "template_talk": 11,
 46+ "help": 12,
 47+ "help_talk": 13,
 48+ "category": 14,
 49+ "category_talk": 15,
 50+ "image": 6,
 51+ "image_talk": 7,
 52+ "project": 4,
 53+ "project_talk": 5,
 54+ /* testing custom / alias */
 55+ "penguins": 100,
 56+ "antarctic_waterfowl": 100
 57+ },
 58+ "wgCaseSensitiveNamespaces": []
 59+ });
 60+};
 61+
 62+test( '-- Initial check', function() {
 63+ expect(1);
 64+ ok( mw.Title, 'mw.Title defined' );
 65+});
 66+
 67+test( 'Transform between Text and Db', function() {
 68+ expect(2);
 69+ _titleConfig();
 70+
 71+ var title;
 72+
 73+ title = new mw.Title( 'File:quux pif.jpg' );
 74+ equal( title.getName(), 'Quux_pif' );
 75+
 76+ title = new mw.Title( 'File:Glarg_foo_glang.jpg' );
 77+ equal( title.getNameText(), 'Glarg foo glang' );
 78+});
 79+
 80+test( 'Main text for filename', function() {
 81+ expect(8);
 82+ _titleConfig();
 83+
 84+ var title = new mw.Title( 'File:foo_bar.JPG' );
 85+
 86+ equal( title.getNamespaceId(), 6 );
 87+ equal( title.getNamespacePrefix(), 'File:' );
 88+ equal( title.getName(), 'Foo_bar' );
 89+ equal( title.getNameText(), 'Foo bar' );
 90+ equal( title.getMain(), 'Foo_bar.jpg' );
 91+ equal( title.getMainText(), 'Foo bar.jpg' );
 92+ equal( title.getExtension(), 'jpg' );
 93+ equal( title.getDotExtension(), '.jpg' );
 94+});
 95+
 96+test( 'Namespace detection and conversion', function() {
 97+ expect(6);
 98+ _titleConfig();
 99+
 100+ var title;
 101+
 102+ title = new mw.Title( 'something.PDF', 6 );
 103+ equal( title.toString(), 'File:Something.pdf' );
 104+
 105+ title = new mw.Title( 'NeilK', 3 );
 106+ equal( title.toString(), 'User_talk:NeilK' );
 107+ equal( title.toText(), 'User talk:NeilK' );
 108+
 109+ title = new mw.Title( 'Frobisher', 100 );
 110+ equal( title.toString(), 'Penguins:Frobisher' );
 111+
 112+ title = new mw.Title( 'antarctic_waterfowl:flightless_yet_cute.jpg' );
 113+ equal( title.toString(), 'Penguins:Flightless_yet_cute.jpg' );
 114+
 115+ title = new mw.Title( 'Penguins:flightless_yet_cute.jpg' );
 116+ equal( title.toString(), 'Penguins:Flightless_yet_cute.jpg' );
 117+});
 118+
 119+test( 'Throw error on invalid title', function() {
 120+ expect(1);
 121+ _titleConfig();
 122+
 123+ raises(function() {
 124+ var title = new mw.Title( '' );
 125+ }, 'Throw error on empty string' );
 126+});
 127+
 128+test( 'Case-sensivity', function() {
 129+ expect(3);
 130+ _titleConfig();
 131+
 132+ var title;
 133+
 134+ // Default config
 135+ mw.config.set( 'wgCaseSensitiveNamespaces', [] );
 136+
 137+ title = new mw.Title( 'article' );
 138+ equal( title.toString(), 'Article', 'Default config: No sensitive namespaces by default. First-letter becomes uppercase' );
 139+
 140+ // $wgCapitalLinks = false;
 141+ mw.config.set( 'wgCaseSensitiveNamespaces', [0, -2, 1, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15] );
 142+
 143+ title = new mw.Title( 'article' );
 144+ equal( title.toString(), 'article', '$wgCapitalLinks=false: Article namespace is sensitive, first-letter case stays lowercase' );
 145+
 146+ title = new mw.Title( 'john', 2 );
 147+ equal( title.toString(), 'User:John', '$wgCapitalLinks=false: User namespace is insensitive, first-letter becomes uppercase' );
 148+});
 149+
 150+test( 'toString / toText', function() {
 151+ expect(2);
 152+ _titleConfig();
 153+
 154+ var title = new mw.Title( 'Some random page' );
 155+
 156+ equal( title.toString(), title.getPrefixedDb() );
 157+ equal( title.toText(), title.getPrefixedText() );
 158+});
 159+
 160+test( 'Exists', function() {
 161+ expect(3);
 162+ _titleConfig();
 163+
 164+ var title;
 165+
 166+ // Empty registry, checks default to null
 167+
 168+ title = new mw.Title( 'Some random page', 4 );
 169+ strictEqual( title.exists(), null, 'Return null with empty existance registry' );
 170+
 171+ // Basic registry, checks default to boolean
 172+ mw.Title.exist.set( ['Does_exist', 'User_talk:NeilK', 'Wikipedia:Sandbox_rules'], true );
 173+ mw.Title.exist.set( ['Does_not_exist', 'User:John', 'Foobar'], false );
 174+
 175+ title = new mw.Title( 'Project:Sandbox rules' );
 176+ assertTrue( title.exists(), 'Return true for page titles marked as existing' );
 177+ title = new mw.Title( 'Foobar' );
 178+ assertFalse( title.exists(), 'Return false for page titles marked as inexisting' );
 179+
 180+});
 181+
 182+test( 'Url', function() {
 183+ expect(2);
 184+ _titleConfig();
 185+
 186+ var title;
 187+
 188+ // Config
 189+ mw.config.set( 'wgArticlePath', '/wiki/$1' );
 190+
 191+ title = new mw.Title( 'Foobar' );
 192+ equal( title.getUrl(), '/wiki/Foobar', 'Basic functionally, toString passing to wikiGetlink' );
 193+
 194+ title = new mw.Title( 'John Doe', 3 );
 195+ equal( title.getUrl(), '/wiki/User_talk:John_Doe', 'Escaping in title and namespace for urls' );
 196+});
Property changes on: trunk/phase3/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js
___________________________________________________________________
Added: svn:eol-style
1197 + native
Index: trunk/phase3/tests/jasmine/SpecRunner.html
@@ -10,18 +10,17 @@
1111 <!-- include source files here... -->
1212 <script type="text/javascript" src="../../load.php?debug=true&lang=en&modules=jquery%7Cmediawiki&only=scripts&skin=vector"></script>
1313
14 - <script type="text/javascript" src="../../resources/mediawiki/mediawiki.uri.js"></script>
 14+ <script type="text/javascript" src="../../resources/mediawiki/mediawiki.Uri.js"></script>
1515
1616 <!-- include spec files here... -->
17 - <script type="text/javascript" src="spec/mediawiki.uri.spec.js"></script>
 17+ <script type="text/javascript" src="spec/mediawiki.Uri.spec.js"></script>
1818
1919 </head>
2020 <body>
2121 <script type="text/javascript">
22 - jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
 22+ jasmine.getEnv().addReporter( new jasmine.TrivialReporter() );
2323 jasmine.getEnv().execute();
2424 </script>
2525
2626 </body>
2727 </html>
28 -
Index: trunk/phase3/tests/jasmine/spec/mediawiki.uri.spec.js
@@ -1,274 +0,0 @@
2 -( function() {
3 -
4 - describe( "mw.Uri", function() {
5 -
6 - describe( "should work well in loose and strict mode", function() {
7 -
8 - function basicTests( strict ) {
9 -
10 - describe( "should parse a simple HTTP URI correctly", function() {
11 -
12 - var uriString = 'http://www.ietf.org/rfc/rfc2396.txt';
13 - var uri;
14 - if ( strict ) {
15 - uri = new mw.Uri( uriString, strict );
16 - } else {
17 - uri = new mw.Uri( uriString );
18 - }
19 -
20 - it( "should have basic object properties", function() {
21 - expect( uri.protocol ).toEqual( 'http' );
22 - expect( uri.host ).toEqual( 'www.ietf.org' );
23 - expect( uri.port ).not.toBeDefined();
24 - expect( uri.path ).toEqual( '/rfc/rfc2396.txt' );
25 - expect( uri.query ).toEqual( {} );
26 - expect( uri.fragment ).not.toBeDefined();
27 - } );
28 -
29 - describe( "should construct composite components of URI on request", function() {
30 - it( "should have empty userinfo", function() {
31 - expect( uri.getUserInfo() ).toEqual( '' );
32 - } );
33 -
34 - it( "should have authority equal to host", function() {
35 - expect( uri.getAuthority() ).toEqual( 'www.ietf.org' );
36 - } );
37 -
38 - it( "should have hostport equal to host", function() {
39 - expect( uri.getHostPort() ).toEqual( 'www.ietf.org' );
40 - } );
41 -
42 - it( "should have empty string as query string", function() {
43 - expect( uri.getQueryString() ).toEqual( '' );
44 - } );
45 -
46 - it( "should have path as relative path", function() {
47 - expect( uri.getRelativePath() ).toEqual( '/rfc/rfc2396.txt' );
48 - } );
49 -
50 - it( "should return a uri string equivalent to original", function() {
51 - expect( uri.toString() ).toEqual( uriString );
52 - } );
53 - } );
54 - } );
55 - }
56 -
57 - describe( "should work in loose mode", function() {
58 - basicTests( false );
59 - } );
60 -
61 - describe( "should work in strict mode", function() {
62 - basicTests( true );
63 - } );
64 -
65 - } );
66 -
67 - it( "should parse a simple ftp URI correctly with user and password", function() {
68 - var uri = new mw.Uri( 'ftp://usr:pwd@192.0.2.16/' );
69 - expect( uri.protocol ).toEqual( 'ftp' );
70 - expect( uri.user ).toEqual( 'usr' );
71 - expect( uri.password ).toEqual( 'pwd' );
72 - expect( uri.host ).toEqual( '192.0.2.16' );
73 - expect( uri.port ).not.toBeDefined();
74 - expect( uri.path ).toEqual( '/' );
75 - expect( uri.query ).toEqual( {} );
76 - expect( uri.fragment ).not.toBeDefined();
77 - } );
78 -
79 - it( "should parse a simple querystring", function() {
80 - var uri = new mw.Uri( 'http://www.google.com/?q=uri' );
81 - expect( uri.protocol ).toEqual( 'http' );
82 - expect( uri.host ).toEqual( 'www.google.com' );
83 - expect( uri.port ).not.toBeDefined();
84 - expect( uri.path ).toEqual( '/' );
85 - expect( uri.query ).toBeDefined();
86 - expect( uri.query ).toEqual( { q: 'uri' } );
87 - expect( uri.fragment ).not.toBeDefined();
88 - expect( uri.getQueryString() ).toEqual( 'q=uri' );
89 - } );
90 -
91 - describe( "should handle multiple value query args", function() {
92 - var uri = new mw.Uri( 'http://www.sample.com/dir/?m=foo&m=bar&n=1' );
93 - it ( "should parse with multiple values", function() {
94 - expect( uri.query.m.length ).toEqual( 2 );
95 - expect( uri.query.m[0] ).toEqual( 'foo' );
96 - expect( uri.query.m[1] ).toEqual( 'bar' );
97 - expect( uri.query.n ).toEqual( '1' );
98 - } );
99 - it ( "should accept multiple values", function() {
100 - uri.query.n = [ "x", "y", "z" ];
101 - expect( uri.toString() ).toContain( 'm=foo&m=bar' );
102 - expect( uri.toString() ).toContain( 'n=x&n=y&n=z' );
103 - expect( uri.toString().length ).toEqual( 'http://www.sample.com/dir/?m=foo&m=bar&n=x&n=y&n=z'.length );
104 - } );
105 - it ( "should be okay with removing values", function() {
106 - uri.query.m.splice( 0, 1 );
107 - delete uri.query.n;
108 - expect( uri.toString() ).toEqual( 'http://www.sample.com/dir/?m=bar' );
109 - uri.query.m.splice( 0, 1 );
110 - expect( uri.toString() ).toEqual( 'http://www.sample.com/dir/' );
111 - } );
112 - } );
113 -
114 - describe( "should deal with an all-dressed URI with everything", function() {
115 - var uri = new mw.Uri( 'http://auth@www.sample.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=value+%28escaped%29#top' );
116 -
117 - it( "should have basic object properties", function() {
118 - expect( uri.protocol ).toEqual( 'http' );
119 - expect( uri.user ).toEqual( 'auth' );
120 - expect( uri.password ).not.toBeDefined();
121 - expect( uri.host ).toEqual( 'www.sample.com' );
122 - expect( uri.port ).toEqual( '81' );
123 - expect( uri.path ).toEqual( '/dir/dir.2/index.htm' );
124 - expect( uri.query ).toEqual( { q1: '0', test1: null, test2: 'value (escaped)' } );
125 - expect( uri.fragment ).toEqual( 'top' );
126 - } );
127 -
128 - describe( "should construct composite components of URI on request", function() {
129 - it( "should have userinfo", function() {
130 - expect( uri.getUserInfo() ).toEqual( 'auth' );
131 - } );
132 -
133 - it( "should have authority equal to auth@hostport", function() {
134 - expect( uri.getAuthority() ).toEqual( 'auth@www.sample.com:81' );
135 - } );
136 -
137 - it( "should have hostport equal to host:port", function() {
138 - expect( uri.getHostPort() ).toEqual( 'www.sample.com:81' );
139 - } );
140 -
141 - it( "should have query string which contains all components", function() {
142 - var queryString = uri.getQueryString();
143 - expect( queryString ).toContain( 'q1=0' );
144 - expect( queryString ).toContain( 'test1' );
145 - expect( queryString ).not.toContain( 'test1=' );
146 - expect( queryString ).toContain( 'test2=value+%28escaped%29' );
147 - } );
148 -
149 - it( "should have path as relative path", function() {
150 - expect( uri.getRelativePath() ).toContain( uri.path );
151 - expect( uri.getRelativePath() ).toContain( uri.getQueryString() );
152 - expect( uri.getRelativePath() ).toContain( uri.fragment );
153 - } );
154 -
155 - } );
156 - } );
157 -
158 - describe( "should be able to clone itself", function() {
159 - var original = new mw.Uri( 'http://en.wiki.local/w/api.php?action=query&foo=bar' );
160 - var clone = original.clone();
161 -
162 - it( "should make clones equivalent", function() {
163 - expect( original ).toEqual( clone );
164 - expect( original.toString() ).toEqual( clone.toString() );
165 - } );
166 -
167 - it( "should be able to manipulate clones independently", function() {
168 - // but they are still different objects
169 - expect( original ).not.toBe( clone );
170 - // and can diverge
171 - clone.host = 'fr.wiki.local';
172 - expect( original.host ).not.toEqual( clone.host );
173 - expect( original.toString() ).not.toEqual( clone.toString() );
174 - } );
175 - } );
176 -
177 - describe( "should be able to construct URL from object", function() {
178 - it ( "should construct given basic arguments", function() {
179 - var uri = new mw.Uri( { protocol: 'http', host: 'www.foo.local', path: '/this' } );
180 - expect( uri.toString() ).toEqual( 'http://www.foo.local/this' );
181 - } );
182 -
183 - it ( "should construct given more complex arguments", function() {
184 - var uri = new mw.Uri( {
185 - protocol: 'http',
186 - host: 'www.foo.local',
187 - path: '/this',
188 - query: { hi: 'there' },
189 - fragment: 'blah'
190 - } );
191 - expect( uri.toString() ).toEqual( 'http://www.foo.local/this?hi=there#blah' );
192 - } );
193 -
194 - it ( "should fail to construct without required properties", function() {
195 - expect( function() {
196 - var uri = new mw.Uri( { protocol: 'http', host: 'www.foo.local' } );
197 - } ).toThrow( "Bad constructor arguments" );
198 - } );
199 - } );
200 -
201 - describe( "should be able to manipulate properties", function() {
202 - var uri;
203 -
204 - beforeEach( function() {
205 - uri = new mw.Uri( 'http://en.wiki.local/w/api.php' );
206 - } );
207 -
208 - it( "can add a fragment", function() {
209 - uri.fragment = 'frag';
210 - expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php#frag' );
211 - } );
212 -
213 - it( "can change host and port", function() {
214 - uri.host = 'fr.wiki.local';
215 - uri.port = '8080';
216 - expect( uri.toString() ).toEqual( 'http://fr.wiki.local:8080/w/api.php' );
217 - } );
218 -
219 - it ( "can add query arguments", function() {
220 - uri.query.foo = 'bar';
221 - expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php?foo=bar' );
222 - } );
223 -
224 - it ( "can extend query arguments", function() {
225 - uri.query.foo = 'bar';
226 - expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php?foo=bar' );
227 - uri.extend( { foo: 'quux', pif: 'paf' } );
228 - expect( uri.toString() ).toContain( 'foo=quux' );
229 - expect( uri.toString() ).not.toContain( 'foo=bar' );
230 - expect( uri.toString() ).toContain( 'pif=paf' );
231 - } );
232 -
233 - it ( "can remove query arguments", function() {
234 - uri.query.foo = 'bar';
235 - expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php?foo=bar' );
236 - delete( uri.query.foo );
237 - expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php' );
238 - } );
239 -
240 - } );
241 -
242 - it( "should throw error on no arguments to constructor", function() {
243 - expect( function() {
244 - uri = new mw.Uri();
245 - } ).toThrow( "Bad constructor arguments" );
246 - } );
247 -
248 - it( "should throw error on empty string as argument to constructor", function() {
249 - expect( function() {
250 - uri = new mw.Uri( '' );
251 - } ).toThrow( "Bad constructor arguments" );
252 - } );
253 -
254 - it( "should throw error on non-URI as argument to constructor", function() {
255 - expect( function() {
256 - uri = new mw.Uri( 'glaswegian penguins' );
257 - } ).toThrow( "Bad constructor arguments" );
258 - } );
259 -
260 - it( "should throw error on improper URI as argument to constructor", function() {
261 - expect( function() {
262 - uri = new mw.Uri( 'http:/foo.com' );
263 - } ).toThrow( "Bad constructor arguments" );
264 - } );
265 -
266 - it( "should throw error on URI without protocol as argument to constructor", function() {
267 - expect( function() {
268 - uri = new mw.Uri( 'foo.com/bar/baz' );
269 - } ).toThrow( "Bad constructor arguments" );
270 - } );
271 -
272 -
273 - } );
274 -
275 -} )();
Index: trunk/phase3/tests/jasmine/spec/mediawiki.Uri.spec.js
@@ -0,0 +1,274 @@
 2+( function() {
 3+
 4+ describe( "mw.Uri", function() {
 5+
 6+ describe( "should work well in loose and strict mode", function() {
 7+
 8+ function basicTests( strict ) {
 9+
 10+ describe( "should parse a simple HTTP URI correctly", function() {
 11+
 12+ var uriString = 'http://www.ietf.org/rfc/rfc2396.txt';
 13+ var uri;
 14+ if ( strict ) {
 15+ uri = new mw.Uri( uriString, strict );
 16+ } else {
 17+ uri = new mw.Uri( uriString );
 18+ }
 19+
 20+ it( "should have basic object properties", function() {
 21+ expect( uri.protocol ).toEqual( 'http' );
 22+ expect( uri.host ).toEqual( 'www.ietf.org' );
 23+ expect( uri.port ).not.toBeDefined();
 24+ expect( uri.path ).toEqual( '/rfc/rfc2396.txt' );
 25+ expect( uri.query ).toEqual( {} );
 26+ expect( uri.fragment ).not.toBeDefined();
 27+ } );
 28+
 29+ describe( "should construct composite components of URI on request", function() {
 30+ it( "should have empty userinfo", function() {
 31+ expect( uri.getUserInfo() ).toEqual( '' );
 32+ } );
 33+
 34+ it( "should have authority equal to host", function() {
 35+ expect( uri.getAuthority() ).toEqual( 'www.ietf.org' );
 36+ } );
 37+
 38+ it( "should have hostport equal to host", function() {
 39+ expect( uri.getHostPort() ).toEqual( 'www.ietf.org' );
 40+ } );
 41+
 42+ it( "should have empty string as query string", function() {
 43+ expect( uri.getQueryString() ).toEqual( '' );
 44+ } );
 45+
 46+ it( "should have path as relative path", function() {
 47+ expect( uri.getRelativePath() ).toEqual( '/rfc/rfc2396.txt' );
 48+ } );
 49+
 50+ it( "should return a uri string equivalent to original", function() {
 51+ expect( uri.toString() ).toEqual( uriString );
 52+ } );
 53+ } );
 54+ } );
 55+ }
 56+
 57+ describe( "should work in loose mode", function() {
 58+ basicTests( false );
 59+ } );
 60+
 61+ describe( "should work in strict mode", function() {
 62+ basicTests( true );
 63+ } );
 64+
 65+ } );
 66+
 67+ it( "should parse a simple ftp URI correctly with user and password", function() {
 68+ var uri = new mw.Uri( 'ftp://usr:pwd@192.0.2.16/' );
 69+ expect( uri.protocol ).toEqual( 'ftp' );
 70+ expect( uri.user ).toEqual( 'usr' );
 71+ expect( uri.password ).toEqual( 'pwd' );
 72+ expect( uri.host ).toEqual( '192.0.2.16' );
 73+ expect( uri.port ).not.toBeDefined();
 74+ expect( uri.path ).toEqual( '/' );
 75+ expect( uri.query ).toEqual( {} );
 76+ expect( uri.fragment ).not.toBeDefined();
 77+ } );
 78+
 79+ it( "should parse a simple querystring", function() {
 80+ var uri = new mw.Uri( 'http://www.google.com/?q=uri' );
 81+ expect( uri.protocol ).toEqual( 'http' );
 82+ expect( uri.host ).toEqual( 'www.google.com' );
 83+ expect( uri.port ).not.toBeDefined();
 84+ expect( uri.path ).toEqual( '/' );
 85+ expect( uri.query ).toBeDefined();
 86+ expect( uri.query ).toEqual( { q: 'uri' } );
 87+ expect( uri.fragment ).not.toBeDefined();
 88+ expect( uri.getQueryString() ).toEqual( 'q=uri' );
 89+ } );
 90+
 91+ describe( "should handle multiple value query args", function() {
 92+ var uri = new mw.Uri( 'http://www.sample.com/dir/?m=foo&m=bar&n=1' );
 93+ it ( "should parse with multiple values", function() {
 94+ expect( uri.query.m.length ).toEqual( 2 );
 95+ expect( uri.query.m[0] ).toEqual( 'foo' );
 96+ expect( uri.query.m[1] ).toEqual( 'bar' );
 97+ expect( uri.query.n ).toEqual( '1' );
 98+ } );
 99+ it ( "should accept multiple values", function() {
 100+ uri.query.n = [ "x", "y", "z" ];
 101+ expect( uri.toString() ).toContain( 'm=foo&m=bar' );
 102+ expect( uri.toString() ).toContain( 'n=x&n=y&n=z' );
 103+ expect( uri.toString().length ).toEqual( 'http://www.sample.com/dir/?m=foo&m=bar&n=x&n=y&n=z'.length );
 104+ } );
 105+ it ( "should be okay with removing values", function() {
 106+ uri.query.m.splice( 0, 1 );
 107+ delete uri.query.n;
 108+ expect( uri.toString() ).toEqual( 'http://www.sample.com/dir/?m=bar' );
 109+ uri.query.m.splice( 0, 1 );
 110+ expect( uri.toString() ).toEqual( 'http://www.sample.com/dir/' );
 111+ } );
 112+ } );
 113+
 114+ describe( "should deal with an all-dressed URI with everything", function() {
 115+ var uri = new mw.Uri( 'http://auth@www.sample.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=value+%28escaped%29#top' );
 116+
 117+ it( "should have basic object properties", function() {
 118+ expect( uri.protocol ).toEqual( 'http' );
 119+ expect( uri.user ).toEqual( 'auth' );
 120+ expect( uri.password ).not.toBeDefined();
 121+ expect( uri.host ).toEqual( 'www.sample.com' );
 122+ expect( uri.port ).toEqual( '81' );
 123+ expect( uri.path ).toEqual( '/dir/dir.2/index.htm' );
 124+ expect( uri.query ).toEqual( { q1: '0', test1: null, test2: 'value (escaped)' } );
 125+ expect( uri.fragment ).toEqual( 'top' );
 126+ } );
 127+
 128+ describe( "should construct composite components of URI on request", function() {
 129+ it( "should have userinfo", function() {
 130+ expect( uri.getUserInfo() ).toEqual( 'auth' );
 131+ } );
 132+
 133+ it( "should have authority equal to auth@hostport", function() {
 134+ expect( uri.getAuthority() ).toEqual( 'auth@www.sample.com:81' );
 135+ } );
 136+
 137+ it( "should have hostport equal to host:port", function() {
 138+ expect( uri.getHostPort() ).toEqual( 'www.sample.com:81' );
 139+ } );
 140+
 141+ it( "should have query string which contains all components", function() {
 142+ var queryString = uri.getQueryString();
 143+ expect( queryString ).toContain( 'q1=0' );
 144+ expect( queryString ).toContain( 'test1' );
 145+ expect( queryString ).not.toContain( 'test1=' );
 146+ expect( queryString ).toContain( 'test2=value+%28escaped%29' );
 147+ } );
 148+
 149+ it( "should have path as relative path", function() {
 150+ expect( uri.getRelativePath() ).toContain( uri.path );
 151+ expect( uri.getRelativePath() ).toContain( uri.getQueryString() );
 152+ expect( uri.getRelativePath() ).toContain( uri.fragment );
 153+ } );
 154+
 155+ } );
 156+ } );
 157+
 158+ describe( "should be able to clone itself", function() {
 159+ var original = new mw.Uri( 'http://en.wiki.local/w/api.php?action=query&foo=bar' );
 160+ var clone = original.clone();
 161+
 162+ it( "should make clones equivalent", function() {
 163+ expect( original ).toEqual( clone );
 164+ expect( original.toString() ).toEqual( clone.toString() );
 165+ } );
 166+
 167+ it( "should be able to manipulate clones independently", function() {
 168+ // but they are still different objects
 169+ expect( original ).not.toBe( clone );
 170+ // and can diverge
 171+ clone.host = 'fr.wiki.local';
 172+ expect( original.host ).not.toEqual( clone.host );
 173+ expect( original.toString() ).not.toEqual( clone.toString() );
 174+ } );
 175+ } );
 176+
 177+ describe( "should be able to construct URL from object", function() {
 178+ it ( "should construct given basic arguments", function() {
 179+ var uri = new mw.Uri( { protocol: 'http', host: 'www.foo.local', path: '/this' } );
 180+ expect( uri.toString() ).toEqual( 'http://www.foo.local/this' );
 181+ } );
 182+
 183+ it ( "should construct given more complex arguments", function() {
 184+ var uri = new mw.Uri( {
 185+ protocol: 'http',
 186+ host: 'www.foo.local',
 187+ path: '/this',
 188+ query: { hi: 'there' },
 189+ fragment: 'blah'
 190+ } );
 191+ expect( uri.toString() ).toEqual( 'http://www.foo.local/this?hi=there#blah' );
 192+ } );
 193+
 194+ it ( "should fail to construct without required properties", function() {
 195+ expect( function() {
 196+ var uri = new mw.Uri( { protocol: 'http', host: 'www.foo.local' } );
 197+ } ).toThrow( "Bad constructor arguments" );
 198+ } );
 199+ } );
 200+
 201+ describe( "should be able to manipulate properties", function() {
 202+ var uri;
 203+
 204+ beforeEach( function() {
 205+ uri = new mw.Uri( 'http://en.wiki.local/w/api.php' );
 206+ } );
 207+
 208+ it( "can add a fragment", function() {
 209+ uri.fragment = 'frag';
 210+ expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php#frag' );
 211+ } );
 212+
 213+ it( "can change host and port", function() {
 214+ uri.host = 'fr.wiki.local';
 215+ uri.port = '8080';
 216+ expect( uri.toString() ).toEqual( 'http://fr.wiki.local:8080/w/api.php' );
 217+ } );
 218+
 219+ it ( "can add query arguments", function() {
 220+ uri.query.foo = 'bar';
 221+ expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php?foo=bar' );
 222+ } );
 223+
 224+ it ( "can extend query arguments", function() {
 225+ uri.query.foo = 'bar';
 226+ expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php?foo=bar' );
 227+ uri.extend( { foo: 'quux', pif: 'paf' } );
 228+ expect( uri.toString() ).toContain( 'foo=quux' );
 229+ expect( uri.toString() ).not.toContain( 'foo=bar' );
 230+ expect( uri.toString() ).toContain( 'pif=paf' );
 231+ } );
 232+
 233+ it ( "can remove query arguments", function() {
 234+ uri.query.foo = 'bar';
 235+ expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php?foo=bar' );
 236+ delete( uri.query.foo );
 237+ expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php' );
 238+ } );
 239+
 240+ } );
 241+
 242+ it( "should throw error on no arguments to constructor", function() {
 243+ expect( function() {
 244+ uri = new mw.Uri();
 245+ } ).toThrow( "Bad constructor arguments" );
 246+ } );
 247+
 248+ it( "should throw error on empty string as argument to constructor", function() {
 249+ expect( function() {
 250+ uri = new mw.Uri( '' );
 251+ } ).toThrow( "Bad constructor arguments" );
 252+ } );
 253+
 254+ it( "should throw error on non-URI as argument to constructor", function() {
 255+ expect( function() {
 256+ uri = new mw.Uri( 'glaswegian penguins' );
 257+ } ).toThrow( "Bad constructor arguments" );
 258+ } );
 259+
 260+ it( "should throw error on improper URI as argument to constructor", function() {
 261+ expect( function() {
 262+ uri = new mw.Uri( 'http:/foo.com' );
 263+ } ).toThrow( "Bad constructor arguments" );
 264+ } );
 265+
 266+ it( "should throw error on URI without protocol as argument to constructor", function() {
 267+ expect( function() {
 268+ uri = new mw.Uri( 'foo.com/bar/baz' );
 269+ } ).toThrow( "Bad constructor arguments" );
 270+ } );
 271+
 272+
 273+ } );
 274+
 275+} )();
Property changes on: trunk/phase3/tests/jasmine/spec/mediawiki.Uri.spec.js
___________________________________________________________________
Added: svn:eol-style
1276 + native
Index: trunk/phase3/resources/Resources.php
@@ -466,11 +466,11 @@
467467 'scripts' => 'resources/mediawiki/mediawiki.htmlform.js',
468468 ),
469469 'mediawiki.Title' => array(
470 - 'scripts' => 'resources/mediawiki/mediawiki.title.js',
 470+ 'scripts' => 'resources/mediawiki/mediawiki.Title.js',
471471 'dependencies' => 'mediawiki.util',
472472 ),
473473 'mediawiki.Uri' => array(
474 - 'scripts' => 'resources/mediawiki/mediawiki.uri.js',
 474+ 'scripts' => 'resources/mediawiki/mediawiki.Uri.js',
475475 ),
476476 'mediawiki.user' => array(
477477 'scripts' => 'resources/mediawiki/mediawiki.user.js',
Index: trunk/phase3/resources/mediawiki/mediawiki.uri.js
@@ -1,260 +0,0 @@
2 -/**
3 - * Library for simple URI parsing and manipulation. Requires jQuery.
4 - *
5 - * Do not expect full RFC 3986 compliance. Intended to be minimal, but featureful.
6 - * The use cases we have in mind are constructing 'next page' or 'previous page' URLs,
7 - * detecting whether we need to use cross-domain proxies for an API, constructing
8 - * simple URL-based API calls, etc.
9 - *
10 - * Intended to compress very well if you use a JS-parsing minifier.
11 - *
12 - * Dependencies: mw, jQuery
13 - *
14 - * Example:
15 - *
16 - * var uri = new mw.Uri( 'http://foo.com/mysite/mypage.php?quux=2' );
17 - *
18 - * if ( uri.host == 'foo.com' ) {
19 - * uri.host = 'www.foo.com';
20 - * uri.extend( { bar: 1 } );
21 - *
22 - * $( 'a#id1' ).attr( 'href', uri );
23 - * // anchor with id 'id1' now links to http://foo.com/mysite/mypage.php?bar=1&quux=2
24 - *
25 - * $( 'a#id2' ).attr( 'href', uri.clone().extend( { bar: 3, pif: 'paf' } ) );
26 - * // anchor with id 'id2' now links to http://foo.com/mysite/mypage.php?bar=3&quux=2&pif=paf
27 - * }
28 - *
29 - * Parsing here is regex based, so may not work on all URIs, but is good enough for most.
30 - *
31 - * Given a URI like
32 - * 'http://usr:pwd@www.test.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=&test3=value+%28escaped%29&r=1&r=2#top':
33 - * The returned object will have the following properties:
34 - *
35 - * protocol 'http'
36 - * user 'usr'
37 - * password 'pwd'
38 - * host 'www.test.com'
39 - * port '81'
40 - * path '/dir/dir.2/index.htm'
41 - * query {
42 - * q1: 0,
43 - * test1: null,
44 - * test2: '',
45 - * test3: 'value (escaped)'
46 - * r: [1, 2]
47 - * }
48 - * fragment 'top'
49 - *
50 - * n.b. 'password' is not technically allowed for HTTP URIs, but it is possible with other
51 - * sorts of URIs.
52 - * You can modify the properties directly. Then use the toString() method to extract the
53 - * full URI string again.
54 - *
55 - * Parsing based on parseUri 1.2.2 (c) Steven Levithan <stevenlevithan.com> MIT License
56 - * http://stevenlevithan.com/demo/parseuri/js/
57 - *
58 - */
59 -
60 -( function( $ ) {
61 -
62 - /**
63 - * Function that's useful when constructing the URI string -- we frequently encounter the pattern of
64 - * having to add something to the URI as we go, but only if it's present, and to include a character before or after if so.
65 - * @param {String} to prepend, if value not empty
66 - * @param {String} value to include, if not empty
67 - * @param {String} to append, if value not empty
68 - * @param {Boolean} raw -- if true, do not URI encode
69 - * @return {String}
70 - */
71 - function cat( pre, val, post, raw ) {
72 - if ( val === undefined || val === null || val === '' ) {
73 - return '';
74 - } else {
75 - return pre + ( raw ? val : mw.Uri.encode( val ) ) + post;
76 - }
77 - }
78 -
79 - // Regular expressions to parse many common URIs.
80 - var parser = {
81 - strict: /^(?:([^:\/?#]+):)?(?:\/\/(?:(?:([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)?((?:[^?#\/]*\/)*[^?#]*)(?:\?([^#]*))?(?:#(.*))?/,
82 - loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?(?:(?:([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?((?:\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?[^?#\/]*)(?:\?([^#]*))?(?:#(.*))?/
83 - },
84 -
85 - // The order here matches the order of captured matches in the above parser regexes.
86 - properties = [
87 - 'protocol', // http
88 - 'user', // usr
89 - 'password', // pwd
90 - 'host', // www.test.com
91 - 'port', // 81
92 - 'path', // /dir/dir.2/index.htm
93 - 'query', // q1=0&&test1&test2=value (will become { q1: 0, test1: '', test2: 'value' } )
94 - 'fragment' // top
95 - ];
96 -
97 - /**
98 - * Constructs URI object. Throws error if arguments are illegal/impossible, or otherwise don't parse.
99 - * @constructor
100 - * @param {!Object|String} URI string, or an Object with appropriate properties (especially another URI object to clone). Object must have non-blank 'protocol', 'host', and 'path' properties.
101 - * @param {Boolean} strict mode (when parsing a string)
102 - */
103 - mw.Uri = function( uri, strictMode ) {
104 - strictMode = !!strictMode;
105 - if ( uri !== undefined && uri !== null || uri !== '' ) {
106 - if ( typeof uri === 'string' ) {
107 - this._parse( uri, strictMode );
108 - } else if ( typeof uri === 'object' ) {
109 - var _this = this;
110 - $.each( properties, function( i, property ) {
111 - _this[property] = uri[property];
112 - } );
113 - if ( this.query === undefined ) {
114 - this.query = {};
115 - }
116 - }
117 - }
118 - if ( !( this.protocol && this.host && this.path ) ) {
119 - throw new Error( 'Bad constructor arguments' );
120 - }
121 - };
122 -
123 - /**
124 - * Standard encodeURIComponent, with extra stuff to make all browsers work similarly and more compliant with RFC 3986
125 - * Similar to rawurlencode from PHP and our JS library mw.util.rawurlencode, but we also replace space with a +
126 - * @param {String} string
127 - * @return {String} encoded for URI
128 - */
129 - mw.Uri.encode = function( s ) {
130 - return encodeURIComponent( s )
131 - .replace( /!/g, '%21').replace( /'/g, '%27').replace( /\(/g, '%28')
132 - .replace( /\)/g, '%29').replace( /\*/g, '%2A')
133 - .replace( /%20/g, '+' );
134 - };
135 -
136 - /**
137 - * Standard decodeURIComponent, with '+' to space
138 - * @param {String} string encoded for URI
139 - * @return {String} decoded string
140 - */
141 - mw.Uri.decode = function( s ) {
142 - return decodeURIComponent( s ).replace( /\+/g, ' ' );
143 - };
144 -
145 - mw.Uri.prototype = {
146 -
147 - /**
148 - * Parse a string and set our properties accordingly.
149 - * @param {String} URI
150 - * @param {Boolean} strictness
151 - * @return {Boolean} success
152 - */
153 - _parse: function( str, strictMode ) {
154 - var matches = parser[ strictMode ? 'strict' : 'loose' ].exec( str );
155 - var uri = this;
156 - $.each( properties, function( i, property ) {
157 - uri[ property ] = matches[ i+1 ];
158 - } );
159 -
160 - // uri.query starts out as the query string; we will parse it into key-val pairs then make
161 - // that object the "query" property.
162 - // we overwrite query in uri way to make cloning easier, it can use the same list of properties.
163 - var q = {};
164 - // using replace to iterate over a string
165 - if ( uri.query ) {
166 - uri.query.replace( /(?:^|&)([^&=]*)(?:(=)([^&]*))?/g, function ($0, $1, $2, $3) {
167 - if ( $1 ) {
168 - var k = mw.Uri.decode( $1 );
169 - var v = ( $2 === '' || $2 === undefined ) ? null : mw.Uri.decode( $3 );
170 - if ( typeof q[ k ] === 'string' ) {
171 - q[ k ] = [ q[ k ] ];
172 - }
173 - if ( typeof q[ k ] === 'object' ) {
174 - q[ k ].push( v );
175 - } else {
176 - q[ k ] = v;
177 - }
178 - }
179 - } );
180 - }
181 - this.query = q;
182 - },
183 -
184 - /**
185 - * Returns user and password portion of a URI.
186 - * @return {String}
187 - */
188 - getUserInfo: function() {
189 - return cat( '', this.user, cat( ':', this.password, '' ) );
190 - },
191 -
192 - /**
193 - * Gets host and port portion of a URI.
194 - * @return {String}
195 - */
196 - getHostPort: function() {
197 - return this.host + cat( ':', this.port, '' );
198 - },
199 -
200 - /**
201 - * Returns the userInfo and host and port portion of the URI.
202 - * In most real-world URLs, this is simply the hostname, but it is more general.
203 - * @return {String}
204 - */
205 - getAuthority: function() {
206 - return cat( '', this.getUserInfo(), '@' ) + this.getHostPort();
207 - },
208 -
209 - /**
210 - * Returns the query arguments of the URL, encoded into a string
211 - * Does not preserve the order of arguments passed into the URI. Does handle escaping.
212 - * @return {String}
213 - */
214 - getQueryString: function() {
215 - var args = [];
216 - $.each( this.query, function( key, val ) {
217 - var k = mw.Uri.encode( key );
218 - var vals = val === null ? [ null ] : $.makeArray( val );
219 - $.each( vals, function( i, v ) {
220 - args.push( k + ( v === null ? '' : '=' + mw.Uri.encode( v ) ) );
221 - } );
222 - } );
223 - return args.join( '&' );
224 - },
225 -
226 - /**
227 - * Returns everything after the authority section of the URI
228 - * @return {String}
229 - */
230 - getRelativePath: function() {
231 - return this.path + cat( '?', this.getQueryString(), '', true ) + cat( '#', this.fragment, '' );
232 - },
233 -
234 - /**
235 - * Gets the entire URI string. May not be precisely the same as input due to order of query arguments.
236 - * @return {String} the URI string
237 - */
238 - toString: function() {
239 - return this.protocol + '://' + this.getAuthority() + this.getRelativePath();
240 - },
241 -
242 - /**
243 - * Clone this URI
244 - * @return {Object} new URI object with same properties
245 - */
246 - clone: function() {
247 - return new mw.Uri( this );
248 - },
249 -
250 - /**
251 - * Extend the query -- supply query parameters to override or add to ours
252 - * @param {Object} query parameters in key-val form to override or add
253 - * @return {Object} this URI object
254 - */
255 - extend: function( parameters ) {
256 - $.extend( this.query, parameters );
257 - return this;
258 - }
259 - };
260 -
261 -} )( jQuery );
Index: trunk/phase3/resources/mediawiki/mediawiki.title.js
@@ -1,334 +0,0 @@
2 -/**
3 - * mediaWiki.Title
4 - *
5 - * @author Neil Kandalgaonkar, 2010
6 - * @author Timo Tijhof, 2011
7 - * @since 1.18
8 - *
9 - * Relies on: mw.config (wgFormattedNamespaces, wgNamespaceIds, wgCaseSensitiveNamespaces), mw.util.wikiGetlink
10 - */
11 -( function( $ ) {
12 -
13 - /* Local space */
14 -
15 - /**
16 - * Title
17 - * @constructor
18 - *
19 - * @param title {String} Title of the page. If no second argument given,
20 - * this will be searched for a namespace.
21 - * @param namespace {Number} (optional) Namespace id. If given, title will be taken as-is.
22 - * @return {Title} this
23 - */
24 -var Title = function( title, namespace ) {
25 - this._ns = 0; // integer namespace id
26 - this._name = null; // name in canonical 'database' form
27 - this._ext = null; // extension
28 -
29 - if ( arguments.length === 2 ) {
30 - setNameAndExtension( this, title );
31 - this._ns = fixNsId( namespace );
32 - } else if ( arguments.length === 1 ) {
33 - setAll( this, title );
34 - }
35 - return this;
36 - },
37 -
38 - /**
39 - * Strip some illegal chars: control chars, colon, less than, greater than,
40 - * brackets, braces, pipe, whitespace and normal spaces. This still leaves some insanity
41 - * intact, like unicode bidi chars, but it's a good start..
42 - * @param s {String}
43 - * @return {String}
44 - */
45 - clean = function( s ) {
46 - if ( s !== undefined ) {
47 - return s.replace( /[\x00-\x1f\x23\x3c\x3e\x5b\x5d\x7b\x7c\x7d\x7f\s]+/g, '_' );
48 - }
49 - },
50 -
51 - /**
52 - * Convert db-key to readable text.
53 - * @param s {String}
54 - * @return {String}
55 - */
56 - text = function ( s ) {
57 - if ( s !== null && s !== undefined ) {
58 - return s.replace( /_/g, ' ' );
59 - } else {
60 - return '';
61 - }
62 - },
63 -
64 - /**
65 - * Sanitize name.
66 - */
67 - fixName = function( s ) {
68 - return clean( $.trim( s ) );
69 - },
70 -
71 - /**
72 - * Sanitize name.
73 - */
74 - fixExt = function( s ) {
75 - return clean( s.toLowerCase() );
76 - },
77 -
78 - /**
79 - * Sanitize namespace id.
80 - * @param id {Number} Namespace id.
81 - * @return {Number|Boolean} The id as-is or boolean false if invalid.
82 - */
83 - fixNsId = function( id ) {
84 - // wgFormattedNamespaces is an object of *string* key-vals (ie. arr["0"] not arr[0] )
85 - var ns = mw.config.get( 'wgFormattedNamespaces' )[id.toString()];
86 -
87 - // Check only undefined (may be false-y, such as '' (main namespace) ).
88 - if ( ns === undefined ) {
89 - return false;
90 - } else {
91 - return Number( id );
92 - }
93 - },
94 -
95 - /**
96 - * Get namespace id from namespace name by any known namespace/id pair (localized, canonical or alias).
97 - *
98 - * @example On a German wiki this would return 6 for any of 'File', 'Datei', 'Image' or even 'Bild'.
99 - * @param ns {String} Namespace name (case insensitive, leading/trailing space ignored).
100 - * @return {Number|Boolean} Namespace id or boolean false if unrecognized.
101 - */
102 - getNsIdByName = function( ns ) {
103 - // toLowerCase throws exception on null/undefined. Return early.
104 - if ( ns == null ) {
105 - return false;
106 - }
107 - ns = clean( $.trim( ns.toLowerCase() ) ); // Normalize
108 - var id = mw.config.get( 'wgNamespaceIds' )[ns];
109 - if ( id === undefined ) {
110 - mw.log( 'mw.Title: Unrecognized namespace: ' + ns );
111 - return false;
112 - }
113 - return fixNsId( id );
114 - },
115 -
116 - /**
117 - * Helper to extract namespace, name and extension from a string.
118 - *
119 - * @param title {mw.Title}
120 - * @param raw {String}
121 - * @return {mw.Title}
122 - */
123 - setAll = function( title, s ) {
124 - // In normal browsers the match-array contains null/undefined if there's no match,
125 - // IE returns an empty string.
126 - var matches = s.match( /^(?:([^:]+):)?(.*?)(?:\.(\w{1,5}))?$/ ),
127 - ns_match = getNsIdByName( matches[1] );
128 -
129 - // Namespace must be valid, and title must be a non-empty string.
130 - if ( ns_match && typeof matches[2] === 'string' && matches[2] !== '' ) {
131 - title._ns = ns_match;
132 - title._name = fixName( matches[2] );
133 - if ( typeof matches[3] === 'string' && matches[3] !== '' ) {
134 - title._ext = fixExt( matches[3] );
135 - }
136 - } else {
137 - // Consistency with MediaWiki PHP: Unknown namespace -> fallback to main namespace.
138 - title._ns = 0;
139 - setNameAndExtension( title, s );
140 - }
141 - return title;
142 - },
143 -
144 - /**
145 - * Helper to extract name and extension from a string.
146 - *
147 - * @param title {mw.Title}
148 - * @param raw {String}
149 - * @return {mw.Title}
150 - */
151 - setNameAndExtension = function( title, raw ) {
152 - // In normal browsers the match-array contains null/undefined if there's no match,
153 - // IE returns an empty string.
154 - var matches = raw.match( /^(?:)?(.*?)(?:\.(\w{1,5}))?$/ );
155 -
156 - // Title must be a non-empty string.
157 - if ( typeof matches[1] === 'string' && matches[1] !== '' ) {
158 - title._name = fixName( matches[1] );
159 - if ( typeof matches[2] === 'string' && matches[2] !== '' ) {
160 - title._ext = fixExt( matches[2] );
161 - }
162 - } else {
163 - throw new Error( 'mw.Title: Could not parse title "' + raw + '"' );
164 - }
165 - return title;
166 - };
167 -
168 -
169 - /* Static space */
170 -
171 - /**
172 - * Whether this title exists on the wiki.
173 - * @param title {mixed} prefixed db-key name (string) or instance of Title
174 - * @return {mixed} Boolean true/false if the information is available. Otherwise null.
175 - */
176 - Title.exists = function( title ) {
177 - var type = $.type( title ), obj = Title.exist.pages, match;
178 - if ( type === 'string' ) {
179 - match = obj[title];
180 - } else if ( type === 'object' && title instanceof Title ) {
181 - match = obj[title.toString()];
182 - } else {
183 - throw new Error( 'mw.Title.exists: title must be a string or an instance of Title' );
184 - }
185 - if ( typeof match === 'boolean' ) {
186 - return match;
187 - }
188 - return null;
189 - };
190 -
191 - /**
192 - * @var Title.exist {Object}
193 - */
194 - Title.exist = {
195 - /**
196 - * @var Title.exist.pages {Object} Keyed by PrefixedDb title.
197 - * Boolean true value indicates page does exist.
198 - */
199 - pages: {},
200 - /**
201 - * @example Declare existing titles: Title.exist.set(['User:John_Doe', ...]);
202 - * @example Declare titles inexisting: Title.exist.set(['File:Foo_bar.jpg', ...], false);
203 - * @param titles {String|Array} Title(s) in strict prefixedDb title form.
204 - * @param state {Boolean} (optional) State of the given titles. Defaults to true.
205 - * @return {Boolean}
206 - */
207 - set: function( titles, state ) {
208 - titles = $.isArray( titles ) ? titles : [titles];
209 - state = state === undefined ? true : !!state;
210 - var pages = this.pages, i, len = titles.length;
211 - for ( i = 0; i < len; i++ ) {
212 - pages[ titles[i] ] = state;
213 - }
214 - return true;
215 - }
216 - };
217 -
218 - /* Public methods */
219 -
220 - var fn = {
221 - constructor: Title,
222 -
223 - /**
224 - * Get the namespace number.
225 - * @return {Number}
226 - */
227 - getNamespaceId: function(){
228 - return this._ns;
229 - },
230 -
231 - /**
232 - * Get the namespace prefix (in the content-language).
233 - * In NS_MAIN this is '', otherwise namespace name plus ':'
234 - * @return {String}
235 - */
236 - getNamespacePrefix: function(){
237 - return mw.config.get( 'wgFormattedNamespaces' )[this._ns].replace( / /g, '_' ) + (this._ns === 0 ? '' : ':');
238 - },
239 -
240 - /**
241 - * The name, like "Foo_bar"
242 - * @return {String}
243 - */
244 - getName: function() {
245 - if ( $.inArray( this._ns, mw.config.get( 'wgCaseSensitiveNamespaces' ) ) !== -1 ) {
246 - return this._name;
247 - } else {
248 - return $.ucFirst( this._name );
249 - }
250 - },
251 -
252 - /**
253 - * The name, like "Foo bar"
254 - * @return {String}
255 - */
256 - getNameText: function() {
257 - return text( this.getName() );
258 - },
259 -
260 - /**
261 - * Get full name in prefixed DB form, like File:Foo_bar.jpg,
262 - * most useful for API calls, anything that must identify the "title".
263 - */
264 - getPrefixedDb: function() {
265 - return this.getNamespacePrefix() + this.getMain();
266 - },
267 -
268 - /**
269 - * Get full name in text form, like "File:Foo bar.jpg".
270 - * @return {String}
271 - */
272 - getPrefixedText: function() {
273 - return text( this.getPrefixedDb() );
274 - },
275 -
276 - /**
277 - * The main title (without namespace), like "Foo_bar.jpg"
278 - * @return {String}
279 - */
280 - getMain: function() {
281 - return this.getName() + this.getDotExtension();
282 - },
283 -
284 - /**
285 - * The "text" form, like "Foo bar.jpg"
286 - * @return {String}
287 - */
288 - getMainText: function() {
289 - return text( this.getMain() );
290 - },
291 -
292 - /**
293 - * Get the extension (returns null if there was none)
294 - * @return {String|null} extension
295 - */
296 - getExtension: function() {
297 - return this._ext;
298 - },
299 -
300 - /**
301 - * Convenience method: return string like ".jpg", or "" if no extension
302 - * @return {String}
303 - */
304 - getDotExtension: function() {
305 - return this._ext === null ? '' : '.' + this._ext;
306 - },
307 -
308 - /**
309 - * Return the URL to this title
310 - * @return {String}
311 - */
312 - getUrl: function() {
313 - return mw.util.wikiGetlink( this.toString() );
314 - },
315 -
316 - /**
317 - * Whether this title exists on the wiki.
318 - * @return {mixed} Boolean true/false if the information is available. Otherwise null.
319 - */
320 - exists: function() {
321 - return Title.exists( this );
322 - }
323 - };
324 -
325 - // Alias
326 - fn.toString = fn.getPrefixedDb;
327 - fn.toText = fn.getPrefixedText;
328 -
329 - // Assign
330 - Title.prototype = fn;
331 -
332 - // Expose
333 - mw.Title = Title;
334 -
335 -})(jQuery);
Index: trunk/phase3/resources/mediawiki/mediawiki.Uri.js
@@ -0,0 +1,260 @@
 2+/**
 3+ * Library for simple URI parsing and manipulation. Requires jQuery.
 4+ *
 5+ * Do not expect full RFC 3986 compliance. Intended to be minimal, but featureful.
 6+ * The use cases we have in mind are constructing 'next page' or 'previous page' URLs,
 7+ * detecting whether we need to use cross-domain proxies for an API, constructing
 8+ * simple URL-based API calls, etc.
 9+ *
 10+ * Intended to compress very well if you use a JS-parsing minifier.
 11+ *
 12+ * Dependencies: mw, jQuery
 13+ *
 14+ * Example:
 15+ *
 16+ * var uri = new mw.Uri( 'http://foo.com/mysite/mypage.php?quux=2' );
 17+ *
 18+ * if ( uri.host == 'foo.com' ) {
 19+ * uri.host = 'www.foo.com';
 20+ * uri.extend( { bar: 1 } );
 21+ *
 22+ * $( 'a#id1' ).attr( 'href', uri );
 23+ * // anchor with id 'id1' now links to http://foo.com/mysite/mypage.php?bar=1&quux=2
 24+ *
 25+ * $( 'a#id2' ).attr( 'href', uri.clone().extend( { bar: 3, pif: 'paf' } ) );
 26+ * // anchor with id 'id2' now links to http://foo.com/mysite/mypage.php?bar=3&quux=2&pif=paf
 27+ * }
 28+ *
 29+ * Parsing here is regex based, so may not work on all URIs, but is good enough for most.
 30+ *
 31+ * Given a URI like
 32+ * 'http://usr:pwd@www.test.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=&test3=value+%28escaped%29&r=1&r=2#top':
 33+ * The returned object will have the following properties:
 34+ *
 35+ * protocol 'http'
 36+ * user 'usr'
 37+ * password 'pwd'
 38+ * host 'www.test.com'
 39+ * port '81'
 40+ * path '/dir/dir.2/index.htm'
 41+ * query {
 42+ * q1: 0,
 43+ * test1: null,
 44+ * test2: '',
 45+ * test3: 'value (escaped)'
 46+ * r: [1, 2]
 47+ * }
 48+ * fragment 'top'
 49+ *
 50+ * n.b. 'password' is not technically allowed for HTTP URIs, but it is possible with other
 51+ * sorts of URIs.
 52+ * You can modify the properties directly. Then use the toString() method to extract the
 53+ * full URI string again.
 54+ *
 55+ * Parsing based on parseUri 1.2.2 (c) Steven Levithan <stevenlevithan.com> MIT License
 56+ * http://stevenlevithan.com/demo/parseuri/js/
 57+ *
 58+ */
 59+
 60+( function( $ ) {
 61+
 62+ /**
 63+ * Function that's useful when constructing the URI string -- we frequently encounter the pattern of
 64+ * having to add something to the URI as we go, but only if it's present, and to include a character before or after if so.
 65+ * @param {String} to prepend, if value not empty
 66+ * @param {String} value to include, if not empty
 67+ * @param {String} to append, if value not empty
 68+ * @param {Boolean} raw -- if true, do not URI encode
 69+ * @return {String}
 70+ */
 71+ function cat( pre, val, post, raw ) {
 72+ if ( val === undefined || val === null || val === '' ) {
 73+ return '';
 74+ } else {
 75+ return pre + ( raw ? val : mw.Uri.encode( val ) ) + post;
 76+ }
 77+ }
 78+
 79+ // Regular expressions to parse many common URIs.
 80+ var parser = {
 81+ strict: /^(?:([^:\/?#]+):)?(?:\/\/(?:(?:([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)?((?:[^?#\/]*\/)*[^?#]*)(?:\?([^#]*))?(?:#(.*))?/,
 82+ loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?(?:(?:([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?((?:\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?[^?#\/]*)(?:\?([^#]*))?(?:#(.*))?/
 83+ },
 84+
 85+ // The order here matches the order of captured matches in the above parser regexes.
 86+ properties = [
 87+ 'protocol', // http
 88+ 'user', // usr
 89+ 'password', // pwd
 90+ 'host', // www.test.com
 91+ 'port', // 81
 92+ 'path', // /dir/dir.2/index.htm
 93+ 'query', // q1=0&&test1&test2=value (will become { q1: 0, test1: '', test2: 'value' } )
 94+ 'fragment' // top
 95+ ];
 96+
 97+ /**
 98+ * Constructs URI object. Throws error if arguments are illegal/impossible, or otherwise don't parse.
 99+ * @constructor
 100+ * @param {!Object|String} URI string, or an Object with appropriate properties (especially another URI object to clone). Object must have non-blank 'protocol', 'host', and 'path' properties.
 101+ * @param {Boolean} strict mode (when parsing a string)
 102+ */
 103+ mw.Uri = function( uri, strictMode ) {
 104+ strictMode = !!strictMode;
 105+ if ( uri !== undefined && uri !== null || uri !== '' ) {
 106+ if ( typeof uri === 'string' ) {
 107+ this._parse( uri, strictMode );
 108+ } else if ( typeof uri === 'object' ) {
 109+ var _this = this;
 110+ $.each( properties, function( i, property ) {
 111+ _this[property] = uri[property];
 112+ } );
 113+ if ( this.query === undefined ) {
 114+ this.query = {};
 115+ }
 116+ }
 117+ }
 118+ if ( !( this.protocol && this.host && this.path ) ) {
 119+ throw new Error( 'Bad constructor arguments' );
 120+ }
 121+ };
 122+
 123+ /**
 124+ * Standard encodeURIComponent, with extra stuff to make all browsers work similarly and more compliant with RFC 3986
 125+ * Similar to rawurlencode from PHP and our JS library mw.util.rawurlencode, but we also replace space with a +
 126+ * @param {String} string
 127+ * @return {String} encoded for URI
 128+ */
 129+ mw.Uri.encode = function( s ) {
 130+ return encodeURIComponent( s )
 131+ .replace( /!/g, '%21').replace( /'/g, '%27').replace( /\(/g, '%28')
 132+ .replace( /\)/g, '%29').replace( /\*/g, '%2A')
 133+ .replace( /%20/g, '+' );
 134+ };
 135+
 136+ /**
 137+ * Standard decodeURIComponent, with '+' to space
 138+ * @param {String} string encoded for URI
 139+ * @return {String} decoded string
 140+ */
 141+ mw.Uri.decode = function( s ) {
 142+ return decodeURIComponent( s ).replace( /\+/g, ' ' );
 143+ };
 144+
 145+ mw.Uri.prototype = {
 146+
 147+ /**
 148+ * Parse a string and set our properties accordingly.
 149+ * @param {String} URI
 150+ * @param {Boolean} strictness
 151+ * @return {Boolean} success
 152+ */
 153+ _parse: function( str, strictMode ) {
 154+ var matches = parser[ strictMode ? 'strict' : 'loose' ].exec( str );
 155+ var uri = this;
 156+ $.each( properties, function( i, property ) {
 157+ uri[ property ] = matches[ i+1 ];
 158+ } );
 159+
 160+ // uri.query starts out as the query string; we will parse it into key-val pairs then make
 161+ // that object the "query" property.
 162+ // we overwrite query in uri way to make cloning easier, it can use the same list of properties.
 163+ var q = {};
 164+ // using replace to iterate over a string
 165+ if ( uri.query ) {
 166+ uri.query.replace( /(?:^|&)([^&=]*)(?:(=)([^&]*))?/g, function ($0, $1, $2, $3) {
 167+ if ( $1 ) {
 168+ var k = mw.Uri.decode( $1 );
 169+ var v = ( $2 === '' || $2 === undefined ) ? null : mw.Uri.decode( $3 );
 170+ if ( typeof q[ k ] === 'string' ) {
 171+ q[ k ] = [ q[ k ] ];
 172+ }
 173+ if ( typeof q[ k ] === 'object' ) {
 174+ q[ k ].push( v );
 175+ } else {
 176+ q[ k ] = v;
 177+ }
 178+ }
 179+ } );
 180+ }
 181+ this.query = q;
 182+ },
 183+
 184+ /**
 185+ * Returns user and password portion of a URI.
 186+ * @return {String}
 187+ */
 188+ getUserInfo: function() {
 189+ return cat( '', this.user, cat( ':', this.password, '' ) );
 190+ },
 191+
 192+ /**
 193+ * Gets host and port portion of a URI.
 194+ * @return {String}
 195+ */
 196+ getHostPort: function() {
 197+ return this.host + cat( ':', this.port, '' );
 198+ },
 199+
 200+ /**
 201+ * Returns the userInfo and host and port portion of the URI.
 202+ * In most real-world URLs, this is simply the hostname, but it is more general.
 203+ * @return {String}
 204+ */
 205+ getAuthority: function() {
 206+ return cat( '', this.getUserInfo(), '@' ) + this.getHostPort();
 207+ },
 208+
 209+ /**
 210+ * Returns the query arguments of the URL, encoded into a string
 211+ * Does not preserve the order of arguments passed into the URI. Does handle escaping.
 212+ * @return {String}
 213+ */
 214+ getQueryString: function() {
 215+ var args = [];
 216+ $.each( this.query, function( key, val ) {
 217+ var k = mw.Uri.encode( key );
 218+ var vals = val === null ? [ null ] : $.makeArray( val );
 219+ $.each( vals, function( i, v ) {
 220+ args.push( k + ( v === null ? '' : '=' + mw.Uri.encode( v ) ) );
 221+ } );
 222+ } );
 223+ return args.join( '&' );
 224+ },
 225+
 226+ /**
 227+ * Returns everything after the authority section of the URI
 228+ * @return {String}
 229+ */
 230+ getRelativePath: function() {
 231+ return this.path + cat( '?', this.getQueryString(), '', true ) + cat( '#', this.fragment, '' );
 232+ },
 233+
 234+ /**
 235+ * Gets the entire URI string. May not be precisely the same as input due to order of query arguments.
 236+ * @return {String} the URI string
 237+ */
 238+ toString: function() {
 239+ return this.protocol + '://' + this.getAuthority() + this.getRelativePath();
 240+ },
 241+
 242+ /**
 243+ * Clone this URI
 244+ * @return {Object} new URI object with same properties
 245+ */
 246+ clone: function() {
 247+ return new mw.Uri( this );
 248+ },
 249+
 250+ /**
 251+ * Extend the query -- supply query parameters to override or add to ours
 252+ * @param {Object} query parameters in key-val form to override or add
 253+ * @return {Object} this URI object
 254+ */
 255+ extend: function( parameters ) {
 256+ $.extend( this.query, parameters );
 257+ return this;
 258+ }
 259+ };
 260+
 261+} )( jQuery );
Property changes on: trunk/phase3/resources/mediawiki/mediawiki.Uri.js
___________________________________________________________________
Added: svn:eol-style
1262 + native
Index: trunk/phase3/resources/mediawiki/mediawiki.Title.js
@@ -0,0 +1,334 @@
 2+/**
 3+ * mediaWiki.Title
 4+ *
 5+ * @author Neil Kandalgaonkar, 2010
 6+ * @author Timo Tijhof, 2011
 7+ * @since 1.18
 8+ *
 9+ * Relies on: mw.config (wgFormattedNamespaces, wgNamespaceIds, wgCaseSensitiveNamespaces), mw.util.wikiGetlink
 10+ */
 11+( function( $ ) {
 12+
 13+ /* Local space */
 14+
 15+ /**
 16+ * Title
 17+ * @constructor
 18+ *
 19+ * @param title {String} Title of the page. If no second argument given,
 20+ * this will be searched for a namespace.
 21+ * @param namespace {Number} (optional) Namespace id. If given, title will be taken as-is.
 22+ * @return {Title} this
 23+ */
 24+var Title = function( title, namespace ) {
 25+ this._ns = 0; // integer namespace id
 26+ this._name = null; // name in canonical 'database' form
 27+ this._ext = null; // extension
 28+
 29+ if ( arguments.length === 2 ) {
 30+ setNameAndExtension( this, title );
 31+ this._ns = fixNsId( namespace );
 32+ } else if ( arguments.length === 1 ) {
 33+ setAll( this, title );
 34+ }
 35+ return this;
 36+ },
 37+
 38+ /**
 39+ * Strip some illegal chars: control chars, colon, less than, greater than,
 40+ * brackets, braces, pipe, whitespace and normal spaces. This still leaves some insanity
 41+ * intact, like unicode bidi chars, but it's a good start..
 42+ * @param s {String}
 43+ * @return {String}
 44+ */
 45+ clean = function( s ) {
 46+ if ( s !== undefined ) {
 47+ return s.replace( /[\x00-\x1f\x23\x3c\x3e\x5b\x5d\x7b\x7c\x7d\x7f\s]+/g, '_' );
 48+ }
 49+ },
 50+
 51+ /**
 52+ * Convert db-key to readable text.
 53+ * @param s {String}
 54+ * @return {String}
 55+ */
 56+ text = function ( s ) {
 57+ if ( s !== null && s !== undefined ) {
 58+ return s.replace( /_/g, ' ' );
 59+ } else {
 60+ return '';
 61+ }
 62+ },
 63+
 64+ /**
 65+ * Sanitize name.
 66+ */
 67+ fixName = function( s ) {
 68+ return clean( $.trim( s ) );
 69+ },
 70+
 71+ /**
 72+ * Sanitize name.
 73+ */
 74+ fixExt = function( s ) {
 75+ return clean( s.toLowerCase() );
 76+ },
 77+
 78+ /**
 79+ * Sanitize namespace id.
 80+ * @param id {Number} Namespace id.
 81+ * @return {Number|Boolean} The id as-is or boolean false if invalid.
 82+ */
 83+ fixNsId = function( id ) {
 84+ // wgFormattedNamespaces is an object of *string* key-vals (ie. arr["0"] not arr[0] )
 85+ var ns = mw.config.get( 'wgFormattedNamespaces' )[id.toString()];
 86+
 87+ // Check only undefined (may be false-y, such as '' (main namespace) ).
 88+ if ( ns === undefined ) {
 89+ return false;
 90+ } else {
 91+ return Number( id );
 92+ }
 93+ },
 94+
 95+ /**
 96+ * Get namespace id from namespace name by any known namespace/id pair (localized, canonical or alias).
 97+ *
 98+ * @example On a German wiki this would return 6 for any of 'File', 'Datei', 'Image' or even 'Bild'.
 99+ * @param ns {String} Namespace name (case insensitive, leading/trailing space ignored).
 100+ * @return {Number|Boolean} Namespace id or boolean false if unrecognized.
 101+ */
 102+ getNsIdByName = function( ns ) {
 103+ // toLowerCase throws exception on null/undefined. Return early.
 104+ if ( ns == null ) {
 105+ return false;
 106+ }
 107+ ns = clean( $.trim( ns.toLowerCase() ) ); // Normalize
 108+ var id = mw.config.get( 'wgNamespaceIds' )[ns];
 109+ if ( id === undefined ) {
 110+ mw.log( 'mw.Title: Unrecognized namespace: ' + ns );
 111+ return false;
 112+ }
 113+ return fixNsId( id );
 114+ },
 115+
 116+ /**
 117+ * Helper to extract namespace, name and extension from a string.
 118+ *
 119+ * @param title {mw.Title}
 120+ * @param raw {String}
 121+ * @return {mw.Title}
 122+ */
 123+ setAll = function( title, s ) {
 124+ // In normal browsers the match-array contains null/undefined if there's no match,
 125+ // IE returns an empty string.
 126+ var matches = s.match( /^(?:([^:]+):)?(.*?)(?:\.(\w{1,5}))?$/ ),
 127+ ns_match = getNsIdByName( matches[1] );
 128+
 129+ // Namespace must be valid, and title must be a non-empty string.
 130+ if ( ns_match && typeof matches[2] === 'string' && matches[2] !== '' ) {
 131+ title._ns = ns_match;
 132+ title._name = fixName( matches[2] );
 133+ if ( typeof matches[3] === 'string' && matches[3] !== '' ) {
 134+ title._ext = fixExt( matches[3] );
 135+ }
 136+ } else {
 137+ // Consistency with MediaWiki PHP: Unknown namespace -> fallback to main namespace.
 138+ title._ns = 0;
 139+ setNameAndExtension( title, s );
 140+ }
 141+ return title;
 142+ },
 143+
 144+ /**
 145+ * Helper to extract name and extension from a string.
 146+ *
 147+ * @param title {mw.Title}
 148+ * @param raw {String}
 149+ * @return {mw.Title}
 150+ */
 151+ setNameAndExtension = function( title, raw ) {
 152+ // In normal browsers the match-array contains null/undefined if there's no match,
 153+ // IE returns an empty string.
 154+ var matches = raw.match( /^(?:)?(.*?)(?:\.(\w{1,5}))?$/ );
 155+
 156+ // Title must be a non-empty string.
 157+ if ( typeof matches[1] === 'string' && matches[1] !== '' ) {
 158+ title._name = fixName( matches[1] );
 159+ if ( typeof matches[2] === 'string' && matches[2] !== '' ) {
 160+ title._ext = fixExt( matches[2] );
 161+ }
 162+ } else {
 163+ throw new Error( 'mw.Title: Could not parse title "' + raw + '"' );
 164+ }
 165+ return title;
 166+ };
 167+
 168+
 169+ /* Static space */
 170+
 171+ /**
 172+ * Whether this title exists on the wiki.
 173+ * @param title {mixed} prefixed db-key name (string) or instance of Title
 174+ * @return {mixed} Boolean true/false if the information is available. Otherwise null.
 175+ */
 176+ Title.exists = function( title ) {
 177+ var type = $.type( title ), obj = Title.exist.pages, match;
 178+ if ( type === 'string' ) {
 179+ match = obj[title];
 180+ } else if ( type === 'object' && title instanceof Title ) {
 181+ match = obj[title.toString()];
 182+ } else {
 183+ throw new Error( 'mw.Title.exists: title must be a string or an instance of Title' );
 184+ }
 185+ if ( typeof match === 'boolean' ) {
 186+ return match;
 187+ }
 188+ return null;
 189+ };
 190+
 191+ /**
 192+ * @var Title.exist {Object}
 193+ */
 194+ Title.exist = {
 195+ /**
 196+ * @var Title.exist.pages {Object} Keyed by PrefixedDb title.
 197+ * Boolean true value indicates page does exist.
 198+ */
 199+ pages: {},
 200+ /**
 201+ * @example Declare existing titles: Title.exist.set(['User:John_Doe', ...]);
 202+ * @example Declare titles inexisting: Title.exist.set(['File:Foo_bar.jpg', ...], false);
 203+ * @param titles {String|Array} Title(s) in strict prefixedDb title form.
 204+ * @param state {Boolean} (optional) State of the given titles. Defaults to true.
 205+ * @return {Boolean}
 206+ */
 207+ set: function( titles, state ) {
 208+ titles = $.isArray( titles ) ? titles : [titles];
 209+ state = state === undefined ? true : !!state;
 210+ var pages = this.pages, i, len = titles.length;
 211+ for ( i = 0; i < len; i++ ) {
 212+ pages[ titles[i] ] = state;
 213+ }
 214+ return true;
 215+ }
 216+ };
 217+
 218+ /* Public methods */
 219+
 220+ var fn = {
 221+ constructor: Title,
 222+
 223+ /**
 224+ * Get the namespace number.
 225+ * @return {Number}
 226+ */
 227+ getNamespaceId: function(){
 228+ return this._ns;
 229+ },
 230+
 231+ /**
 232+ * Get the namespace prefix (in the content-language).
 233+ * In NS_MAIN this is '', otherwise namespace name plus ':'
 234+ * @return {String}
 235+ */
 236+ getNamespacePrefix: function(){
 237+ return mw.config.get( 'wgFormattedNamespaces' )[this._ns].replace( / /g, '_' ) + (this._ns === 0 ? '' : ':');
 238+ },
 239+
 240+ /**
 241+ * The name, like "Foo_bar"
 242+ * @return {String}
 243+ */
 244+ getName: function() {
 245+ if ( $.inArray( this._ns, mw.config.get( 'wgCaseSensitiveNamespaces' ) ) !== -1 ) {
 246+ return this._name;
 247+ } else {
 248+ return $.ucFirst( this._name );
 249+ }
 250+ },
 251+
 252+ /**
 253+ * The name, like "Foo bar"
 254+ * @return {String}
 255+ */
 256+ getNameText: function() {
 257+ return text( this.getName() );
 258+ },
 259+
 260+ /**
 261+ * Get full name in prefixed DB form, like File:Foo_bar.jpg,
 262+ * most useful for API calls, anything that must identify the "title".
 263+ */
 264+ getPrefixedDb: function() {
 265+ return this.getNamespacePrefix() + this.getMain();
 266+ },
 267+
 268+ /**
 269+ * Get full name in text form, like "File:Foo bar.jpg".
 270+ * @return {String}
 271+ */
 272+ getPrefixedText: function() {
 273+ return text( this.getPrefixedDb() );
 274+ },
 275+
 276+ /**
 277+ * The main title (without namespace), like "Foo_bar.jpg"
 278+ * @return {String}
 279+ */
 280+ getMain: function() {
 281+ return this.getName() + this.getDotExtension();
 282+ },
 283+
 284+ /**
 285+ * The "text" form, like "Foo bar.jpg"
 286+ * @return {String}
 287+ */
 288+ getMainText: function() {
 289+ return text( this.getMain() );
 290+ },
 291+
 292+ /**
 293+ * Get the extension (returns null if there was none)
 294+ * @return {String|null} extension
 295+ */
 296+ getExtension: function() {
 297+ return this._ext;
 298+ },
 299+
 300+ /**
 301+ * Convenience method: return string like ".jpg", or "" if no extension
 302+ * @return {String}
 303+ */
 304+ getDotExtension: function() {
 305+ return this._ext === null ? '' : '.' + this._ext;
 306+ },
 307+
 308+ /**
 309+ * Return the URL to this title
 310+ * @return {String}
 311+ */
 312+ getUrl: function() {
 313+ return mw.util.wikiGetlink( this.toString() );
 314+ },
 315+
 316+ /**
 317+ * Whether this title exists on the wiki.
 318+ * @return {mixed} Boolean true/false if the information is available. Otherwise null.
 319+ */
 320+ exists: function() {
 321+ return Title.exists( this );
 322+ }
 323+ };
 324+
 325+ // Alias
 326+ fn.toString = fn.getPrefixedDb;
 327+ fn.toText = fn.getPrefixedText;
 328+
 329+ // Assign
 330+ Title.prototype = fn;
 331+
 332+ // Expose
 333+ mw.Title = Title;
 334+
 335+})(jQuery);
Property changes on: trunk/phase3/resources/mediawiki/mediawiki.Title.js
___________________________________________________________________
Added: svn:eol-style
1336 + native

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r94325Apply lowerCamelCase to files for constructors as well....krinkle06:41, 12 August 2011

Status & tagging log