1/** 2 * H.js 3 * 4 * Lightweight, extremely bare-bones library for manipulating the DOM and 5 * saving some typing. 6 */ 7 8var Element = function(domElement) { 9 this.el = domElement; 10}; 11 12/** 13 * Creates a toggle button that adds / removes the given class name from the 14 * given element. 15 * 16 * @param {Element} $el - The element to modify. 17 * @param {string} onClass - The class to add to the given element. 18 * @param {function} onFunc - Additional actions when toggling on. 19 * @param {function} offFunc - Additional actions when toggling off. 20 */ 21Element.prototype.createToggle = function($el, onClass, onFunc, offFunc) { 22 this.on('click', function(e) { 23 if ($el.el.className === '') { 24 $el.el.className = onClass; 25 onFunc(new Element(this), e); 26 } else { 27 $el.el.className = ''; 28 offFunc(new Element(this), e); 29 } 30 e.preventDefault(); 31 }, false); 32}; 33Element.prototype.on = function(event, func) { 34 events = event.split(' '); 35 var el = this.el; 36 if (el == null) { 37 console.error("Error: element for event is null"); 38 return; 39 } 40 var addEvent = function(e) { 41 if (el.addEventListener) { 42 el.addEventListener(e, func, false); 43 } else if (el.attachEvent) { 44 el.attachEvent(e, func); 45 } 46 }; 47 if (events.length === 1) { 48 addEvent(event); 49 } else { 50 for(var i=0; i<events.length; i++) { 51 addEvent(events[i]); 52 } 53 } 54}; 55Element.prototype.setClass = function(className) { 56 if (this.el == null) { 57 console.error("Error: element to set class on is null"); 58 return; 59 } 60 this.el.className = className; 61}; 62Element.prototype.removeClass = function(className) { 63 if (this.el == null) { 64 console.error("Error: element to remove class on is null"); 65 return; 66 } 67 var regex = new RegExp(' ?' + className, 'g'); 68 this.el.className = this.el.className.replace(regex, ''); 69}; 70Element.prototype.text = function(text, className) { 71 if (this.el == null) { 72 console.error("Error: element for setting text is null"); 73 return; 74 } 75 if (this.el.textContent !== text) { 76 this.el.textContent = text; 77 if (typeof className !== 'undefined') { 78 this.el.className = this.el.className + ' ' + className; 79 } 80 } 81}; 82Element.prototype.insertAfter = function(newNode) { 83 if (this.el == null) { 84 console.error("Error: element for insertAfter is null"); 85 return; 86 } 87 this.el.parentNode.insertBefore(newNode, this.el.nextSibling); 88}; 89Element.prototype.remove = function() { 90 if (this.el == null) { 91 console.error("Didn't remove element"); 92 return; 93 } 94 this.el.parentNode.removeChild(this.el); 95}; 96Element.prototype.hide = function() { 97 if (this.el == null) { 98 console.error("Didn't hide element"); 99 return; 100 } 101 this.el.className += ' effect fade-out'; 102}; 103Element.prototype.show = function() { 104 if (this.el == null) { 105 console.error("Didn't show element"); 106 return; 107 } 108 this.el.className += ' effect'; 109}; 110 111 112var H = { 113 getQEl: function(elementQuery) { 114 return new Element(document.querySelector(elementQuery)); 115 }, 116 getEl: function(elementId) { 117 return new Element(document.getElementById(elementId)); 118 }, 119 save: function($el, key) { 120 localStorage.setItem(key, $el.el.value); 121 }, 122 saveClassic: function($titleEl, $el, key) { 123 var out = ""; 124 var title = $titleEl.el.value; 125 if (title !== "") { 126 out = "# "+title+"\n\n"; 127 } 128 out += $el.el.value; 129 localStorage.setItem(key, out); 130 }, 131 load: function($el, key, onlyLoadPopulated, postUpdated) { 132 var val = localStorage.getItem(key); 133 if (onlyLoadPopulated && val == null) { 134 // Do nothing 135 return true; 136 } 137 $el.el.value = val; 138 if (postUpdated != null) { 139 var lastLocalPublishStr = localStorage.getItem(key+'-published'); 140 if (lastLocalPublishStr != null && lastLocalPublishStr != '') { 141 try { 142 var lastLocalPublish = new Date(lastLocalPublishStr); 143 if (postUpdated > lastLocalPublish) { 144 return false; 145 } 146 } catch (e) { 147 console.error("unable to parse draft updated time"); 148 } 149 } 150 } 151 return true; 152 }, 153 loadClassic: function($titleEl, $el, key, onlyLoadPopulated) { 154 var val = localStorage.getItem(key); 155 if (onlyLoadPopulated && val == null) { 156 // Do nothing 157 return; 158 } 159 if (val.indexOf("# ") === 0) { 160 var eol = val.indexOf("\n"); 161 title = val.substring("# ".length, eol); 162 val = val.substring(eol+"\n\n".length); 163 $titleEl.el.value = title; 164 } 165 $el.el.value = val; 166 }, 167 set: function(key, value) { 168 localStorage.setItem(key, value); 169 }, 170 get: function(key, defaultValue) { 171 var val = localStorage.getItem(key); 172 if (val == null) { 173 val = defaultValue; 174 } 175 return val; 176 }, 177 remove: function(key) { 178 localStorage.removeItem(key); 179 }, 180 exists: function(key) { 181 return localStorage.getItem(key) !== null; 182 }, 183 createPost: function(id, editToken, content, created) { 184 var summaryLen = 200; 185 var titleLen = 80; 186 var getPostMeta = function(content) { 187 var eol = content.indexOf("\n"); 188 if (content.indexOf("# ") === 0) { 189 // Title is in the format: 190 // 191 // # Some title 192 var summary = content.substring(eol).trim(); 193 if (summary.length > summaryLen) { 194 summary = summary.substring(0, summaryLen) + "..."; 195 } 196 return { 197 title: content.substring("# ".length, eol), 198 summary: summary, 199 }; 200 } 201 202 var blankLine = content.indexOf("\n\n"); 203 if (blankLine !== -1 && blankLine <= eol && blankLine <= titleLen) { 204 // Title is in the format: 205 // 206 // Some title 207 // 208 // The body starts after that blank line above it. 209 var summary = content.substring(blankLine).trim(); 210 if (summary.length > summaryLen) { 211 summary = summary.substring(0, summaryLen) + "..."; 212 } 213 return { 214 title: content.substring(0, blankLine), 215 summary: summary, 216 }; 217 } 218 219 // TODO: move this to the beginning 220 var title = content.trim(); 221 var summary = ""; 222 if (title.length > titleLen) { 223 // Content can't fit in the title, so figure out the summary 224 summary = title; 225 title = ""; 226 if (summary.length > summaryLen) { 227 summary = summary.substring(0, summaryLen) + "..."; 228 } 229 } else if (eol > 0) { 230 summary = title.substring(eol+1); 231 title = title.substring(0, eol); 232 } 233 return { 234 title: title, 235 summary: summary 236 }; 237 }; 238
239 var post = getPostMeta(content); 240 post.id = id; 241 post.token = editToken; 242 post.created = created ? new Date(created) : new Date(); 243 post.client = "Pad"; 244 245 return post; 246 }, 247 getTitleStrict: function(content) { 248 var eol = content.indexOf("\n"); 249 var title = ""; 250 var newContent = content; 251 if (content.indexOf("# ") === 0) { 252 // Title is in the format: 253 // # Some title 254 if (eol !== -1) { 255 // First line should start with # and end with \n 256 newContent = content.substring(eol).leftTrim(); 257 title = content.substring("# ".length, eol); 258 } 259 } 260 return { 261 title: title, 262 content: newContent 263 }; 264 }, 265}; 266 267var He = { 268 create: function(name) { 269 return document.createElement(name); 270 }, 271 get: function(id) { 272 return document.getElementById(id); 273 }, 274 $: function(selector) { 275 var els = document.querySelectorAll(selector); 276 return els; 277 }, 278 postJSON: function(url, params, callback) { 279 var http = new XMLHttpRequest(); 280 281 http.open("POST", url, true); 282 283 // Send the proper header information along with the request 284 http.setRequestHeader("Content-type", "application/json"); 285 286 http.onreadystatechange = function() { 287 if (http.readyState == 4) { 288 callback(http.status, JSON.parse(http.responseText)); 289 } 290 } 291 http.send(JSON.stringify(params)); 292 }, 293}; 294 295String.prototype.leftTrim = function() { 296 return this.replace(/^\s+/,""); 297};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.