initial commit
[namibia] / public / min / builder / _index.js
1 /*!
2  * Minify URI Builder
3  */
4 var MUB = {
5     _uid : 0,
6     _minRoot : '/min/?',
7     checkRewrite : function () {
8         var testUri = location.pathname.replace(/\/[^\/]*$/, '/rewriteTest.js').substr(1);
9         function fail() {
10             $('#minRewriteFailed')[0].className = 'topNote';
11         }
12         $.ajax({
13             url : '../f=' + testUri + '&' + (new Date()).getTime(),
14             success : function (data) {
15                 if (data === '1') {
16                     MUB._minRoot = '/min/';
17                     $('span.minRoot').html('/min/');
18                 } else
19                     fail();                
20             },
21             error : fail
22         });
23     },
24     /**
25      * Get markup for new source LI element
26      */
27     newLi : function () {
28         return '<li id="li' + MUB._uid + '">http://' + location.host + '/<input type=text size=20>' +
29         ' <button title="Remove">x</button> <button title="Include Earlier">&uarr;</button>' +
30         ' <button title="Include Later">&darr;</button> <span></span></li>';
31     },
32     /**
33      * Add new empty source LI and attach handlers to buttons
34      */
35     addLi : function () {
36         $('#sources').append(MUB.newLi());
37         var li = $('#li' + MUB._uid)[0];
38         $('button[title=Remove]', li).click(function () {
39             $('#results').hide();
40             var hadValue = !!$('input', li)[0].value;
41             $(li).remove();
42         });
43         $('button[title$=Earlier]', li).click(function () {
44             $(li).prev('li').find('input').each(function () {
45                 $('#results').hide();
46                 // this = previous li input
47                 var tmp = this.value;
48                 this.value = $('input', li).val();
49                 $('input', li).val(tmp);
50                 MUB.updateAllTestLinks();
51             });
52         });
53         $('button[title$=Later]', li).click(function () {
54             $(li).next('li').find('input').each(function () {
55                 $('#results').hide();
56                 // this = next li input
57                 var tmp = this.value;
58                 this.value = $('input', li).val();
59                 $('input', li).val(tmp);
60                 MUB.updateAllTestLinks();
61             });
62         });
63         ++MUB._uid;
64     },
65     /**
66      * In the context of a source LI element, this will analyze the URI in
67      * the INPUT and check the URL on the site.
68      */
69     liUpdateTestLink : function () { // call in context of li element
70         if (! $('input', this)[0].value) 
71             return;
72         var li = this;
73         $('span', this).html('');
74         var url = location.protocol + '//' + location.host + '/' +
75                 $('input', this)[0].value.replace(/^\//, '');
76         $.ajax({
77             url : url,
78             complete : function (xhr, stat) {
79                 if ('success' === stat)
80                     $('span', li).html('&#x2713;');
81                 else {
82                     $('span', li).html('<button><b>404! </b> recheck</button>')
83                         .find('button').click(function () {
84                             MUB.liUpdateTestLink.call(li);
85                         });
86                 }
87             },
88             dataType : 'text'
89         });
90     },
91     /**
92      * Check all source URLs
93      */
94     updateAllTestLinks : function () {
95         $('#sources li').each(MUB.liUpdateTestLink);
96     },
97     /**
98      * In a given array of strings, find the character they all have at
99      * a particular index
100      * @param Array arr array of strings
101      * @param Number pos index to check
102      * @return mixed a common char or '' if any do not match
103      */
104     getCommonCharAtPos : function (arr, pos) {
105         var i,
106             l = arr.length,
107             c = arr[0].charAt(pos);
108         if (c === '' || l === 1)
109             return c;
110         for (i = 1; i < l; ++i)
111             if (arr[i].charAt(pos) !== c)
112                 return '';
113         return c;
114     },
115     /**
116      * Get the shortest URI to minify the set of source files
117      * @param Array sources URIs
118      */
119     getBestUri : function (sources) {
120         var pos = 0,
121             base = '',
122             c;
123         while (true) {
124             c = MUB.getCommonCharAtPos(sources, pos);
125             if (c === '')
126                 break;
127             else
128                 base += c;
129             ++pos;
130         }
131         base = base.replace(/[^\/]+$/, '');
132         var uri = MUB._minRoot + 'f=' + sources.join(',');
133         if (base.charAt(base.length - 1) === '/') {
134             // we have a base dir!
135             var basedSources = sources,
136                 i,
137                 l = sources.length;
138             for (i = 0; i < l; ++i) {
139                 basedSources[i] = sources[i].substr(base.length);
140             }
141             base = base.substr(0, base.length - 1);
142             var bUri = MUB._minRoot + 'b=' + base + '&f=' + basedSources.join(',');
143             //window.console && console.log([uri, bUri]);
144             uri = uri.length < bUri.length ? uri : bUri;
145         }
146         return uri;
147     },
148     /**
149      * Create the Minify URI for the sources
150      */
151     update : function () {
152         MUB.updateAllTestLinks();
153         var sources = [],
154             ext = false,
155             fail = false,
156             markup;
157         $('#sources input').each(function () {
158             var m, val;
159             if (! fail && this.value && (m = this.value.match(/\.(css|js)$/))) {
160                 var thisExt = m[1];
161                 if (ext === false)
162                     ext = thisExt; 
163                 else if (thisExt !== ext) {
164                     fail = true;
165                     return alert('extensions must match!');
166                 }
167                 this.value = this.value.replace(/^\//, '');
168                 if (-1 !== $.inArray(this.value, sources)) {
169                     fail = true;
170                     return alert('duplicate file!');
171                 }
172                 sources.push(this.value);
173             } 
174         });
175         if (fail || ! sources.length)
176             return;
177         $('#groupConfig').val("    'keyName' => array('//" + sources.join("', '//") + "'),");
178         var uri = MUB.getBestUri(sources),
179             uriH = uri.replace(/</, '&lt;').replace(/>/, '&gt;').replace(/&/, '&amp;');
180         $('#uriA').html(uriH)[0].href = uri;
181         if (ext === 'js') {
182             markup = '<script type="text/javascript" src="' + uriH + '"></script>';
183         } else {
184             markup = '<link type="text/css" rel="stylesheet" href="' + uriH + '" />';
185         }
186         $('#uriHtml').val(markup);
187         $('#results').show();
188     },
189     /**
190      * Handler for the "Add file +" button
191      */
192     addButtonClick : function () {
193         $('#results').hide();
194         MUB.addLi();
195         MUB.updateAllTestLinks();
196         $('#update').show().click(MUB.update);
197         $('#sources li:last input')[0].focus();
198     },
199     /**
200      * Runs on DOMready
201      */
202     init : function () {
203         $('#jsDidntLoad').remove();
204         $('#app').show();
205         $('#sources').html('');
206         $('#add button').click(MUB.addButtonClick);
207         // make easier to copy text out of
208         $('#uriHtml, #groupConfig, #symlinkOpt').click(function () {
209             this.select();
210         }).focus(function () {
211             this.select();
212         });
213         $('a.ext').attr({target:'_blank'});
214         if (location.hash) {
215             // make links out of URIs from bookmarklet
216             $('#getBm').hide();
217             var i = 0, found = location.hash.substr(1).split(','), l = found.length;
218             $('#bmUris').html('<p><strong>Found by bookmarklet:</strong> /</p>');
219             var $p = $('#bmUris p');
220             for (; i < l; i++) {
221                 $p.append($('<a href=#></a>').text(found[i])[0]);
222                 if (i < (l - 1)) {
223                     $p.append(', /');
224                 }
225             }
226             $('#bmUris a').click(function () {
227                 MUB.addButtonClick();
228                 $('#sources li:last input').val(this.innerHTML);
229                 MUB.liUpdateTestLink.call($('#sources li:last')[0]);
230                 $('#results').hide();
231                 return false;
232             }).attr({title:'Add file +'});
233         } else {
234             // setup bookmarklet 1
235             $.ajax({
236                 url : '../?f=' + location.pathname.replace(/\/[^\/]*$/, '/bm.js').substr(1),
237                 success : function (code) {
238                     $('#bm')[0].href = code
239                         .replace('%BUILDER_URL%', location.href)
240                         .replace(/\n/g, ' ');
241                 },
242                 dataType : 'text'
243             });
244             if ($.browser.msie) {
245                 $('#getBm p:last').append(' Sorry, not supported in MSIE!');
246             }
247             MUB.addButtonClick();
248         }
249         // setup bookmarklet 2
250         $.ajax({
251             url : '../?f=' + location.pathname.replace(/\/[^\/]*$/, '/bm2.js').substr(1),
252             success : function (code) {
253                 $('#bm2')[0].href = code.replace(/\n/g, ' ');
254             },
255             dataType : 'text'
256         });
257         MUB.checkRewrite();
258     }
259 };
260 $(MUB.init);