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