27e368a93ee728e229609384620d310d14213435
[mdref/mdref] / public / index.js
1 "use strict";
2
3 $(function() {
4 var mdref = {
5 log: function log() {
6 console.log.apply(console, arguments);
7 },
8 is_constant: function is_constant(s) {
9 s = s.replace(/v\d+(_\d+)?$/, "");
10 if (s.length < 2) {
11 return false;
12 }
13 return s.toUpperCase(s) === s;
14 },
15 is_variable: function is_variable(s) {
16 return s.substring(0,1) === "$";
17 },
18 type: function type(s, nn) {
19 var i, j, t;
20 // mdref.log("type", s);
21 // nothing
22 if (!s.match(/[a-zA-Z]/)) {
23 return;
24 }
25
26 switch (s) {
27 // types
28 case "void":
29 case "bool":
30 case "int":
31 case "float":
32 case "string":
33 case "resource":
34 case "array":
35 case "object":
36 case "callable":
37 case "mixed":
38 // Zend/SPL
39 case "stdClass":
40 case "Exception":
41 case "ErrorException":
42 case "RuntimeException":
43 case "UnexpectedValueException":
44 case "DomainException":
45 case "InvalidArgumentException":
46 case "BadMethodCallException":
47 case "Closure":
48 case "Generator":
49 case "Countable":
50 case "Serializable":
51 case "Traversable":
52 case "Iterator":
53 case "IteratorAggregate":
54 case "ArrayAccess":
55 case "ArrayObject":
56 case "ArrayIterator":
57 case "RecursiveArrayIterator":
58 case "SeekableIterator":
59 case "SplObserver":
60 case "SplSubject":
61 case "SplObjectStorage":
62 case "JsonSerializable":
63 return "<code>";
64
65 // keywords
66 case "is":
67 if (nn !== "H1") {
68 return;
69 }
70 case "extends":
71 case "implements":
72 if (nn === "H1") {
73 return "<br>&nbsp;<em>";
74 }
75 case "class":
76 case "interface":
77 case "namespace":
78 case "public":
79 case "protected":
80 case "private":
81 case "static":
82 case "final":
83 case "abstract":
84 case "self":
85 case "parent":
86 // phrases
87 case "Optional":
88 case "optional":
89 return "<em>";
90 }
91
92 // class members
93 if (-1 !== (i = s.indexOf("::"))) {
94 t = s.substring(i+2);
95 if (!mdref.is_constant(t) && !mdref.is_variable(t)) {
96 // methods
97 return "<a href=\"" + s.replace(/::|\\/g, "/") + "\">";
98 }
99 }
100 if (-1 !== (j = s.lastIndexOf("\\")) && s.substr(j+1,1) !== "n") {
101 t = s.substring(j+1);
102 if (!mdref.is_constant(t)) {
103 return "<a href=\"" + s.replace(/\\/g, "/").replace(/::|$/, "#") + "\">";
104 }
105 return "<a href=\"" + s.substring(0,j).replace(/\\/g, "/") + "#" + t + "\">";
106 }
107
108 switch (s.toLowerCase()) {
109 // variables
110 default:
111 if (!mdref.is_variable(s)) {
112 break;
113 }
114 // special constants
115 case "null":
116 case "true":
117 case "false":
118 return "<span class=\"var\">";
119 }
120
121 // constants
122 if (mdref.is_constant(s)) {
123 return "<span class=\"constant\">";
124 }
125 },
126 wrap: function wrap(n, nn) {
127 var $n = $(n)
128 var a = [];
129
130 $n.text().split(/([^a-zA-Z0-9_\\\$:]+)/).forEach(function(v) {
131 var t;
132
133 if ((t = mdref.type(v, nn))) {
134 a.push($(t).text(v));
135 } else if (a.length && a[a.length-1].nodeName === "#text") {
136 /* if we already have a text node and the next is also gonna be a text
137 * node, then join them, becuase chrome v30+ or something eats whitespace
138 * for breakfast, lunch and dinner!
139 */
140 a[a.length-1].textContent += v;
141 } else {
142 a.push(document.createTextNode(v));
143 }
144 });
145 $n.replaceWith(a);
146 },
147 walk: function walk(i, e) {
148 // mdref.log("walk", i, e);
149
150 $.each($.makeArray(e.childNodes), function(i, n) {
151 switch (n.nodeName) {
152 case "A":
153 case "BR":
154 case "HR":
155 case "EM":
156 case "CODE":
157 case "SPAN":
158 break;
159 case "#text":
160 mdref.wrap(n, e.nodeName);
161 break;
162 default:
163 mdref.walk(-1, n);
164 break;
165 }
166 });
167 },
168 blink: function blink(c) {
169 var $c = $(c);
170
171 $c.fadeOut("fast").queue(function(next) {
172 this.style.color = "red";
173 next();
174 }).fadeIn("fast").fadeOut("slow").queue(function(next) {
175 this.style.color = "";
176 next();
177 }).fadeIn("slow");
178 },
179 hashchange: function hashchange() {
180 if (location.hash.length > 1) {
181 var hash = location.hash.substring(1);
182 var name = mdref.is_variable(hash) ? ".var" : ".constant";
183 var scrolled = false;
184
185 $(name).each(hash.substring(hash.length-1) === "_" ? function(i, c) {
186 if (c.textContent.substring(0, hash.length) === hash) {
187 if (!scrolled) {
188 $(window).scrollTop($(c).offset().top - 100);
189 scrolled = true;
190 }
191 mdref.blink(c);
192 }
193 } : function(i, c) {
194 if (c.textContent === hash) {
195 $(window).scrollTop($(c).offset().top - 100);
196 mdref.blink(c);
197 return false;
198 }
199 });
200 }
201 }
202 };
203
204 $("h1,h2,h3,h4,h5,h6,p,li,code,td").each(mdref.walk);
205 $(window).on("hashchange", mdref.hashchange);
206 mdref.hashchange();
207 });