1;(function (CodeMirror, Pos) { 2 3 var ldKeywords = []; 4 5 var previousHint; 6 7 function getToken(e, cur){ return e.getTokenAt(cur); } 8 9 function accum(arr, fn, result){ 10 result = result || []; 11 var len = arr.length, 12 _ = function(val){ result.push(val); }; 13 for(var i=0; i < len; i++){ 14 fn(_, arr[i], i); 15 } 16 return result; 17 } 18 19 function keywordsLike(str){ 20 str = str ? String(str).trim() : ""; 21 var result = accum(ldKeywords, function(_, kw){ 22 !str || ~kw.key.indexOf(str) ? _(kw.key) : null; 23 }); 24 25 if(str){ result.sort(relevanceComparator(str)); } 26 27 return accum(result, function(_, kw){ 28 _({ 29 text: kw, 30 className: "cm-meta" 31 }); 32 }); 33 } 34 35 function contextLike(str, doc){ 36 var ctx, key, 37 result = []; 38 39 str = str ? String(str).trim() : ""; 40 41 if(doc && (ctx = doc["@context"])){ 42 for(key in ctx){ 43 if(!ctx.hasOwnProperty(key)){ return; } 44 !str || ~key.indexOf(str) ? result.push({text: key}) : null; 45 } 46 } 47 return result; 48 } 49 50 function relevanceComparator(str){ 51 return function(a, b){ 52 var result = a.indexOf(str) - b.indexOf(str); 53 if(!result){ 54 return a.localeCompare(b); 55 } 56 return result; 57 }; 58 } 59 60 function hidePopover(){ 61 previousHint && previousHint.popover("destroy"); 62 previousHint = null; 63 } 64 65 function showPopover(doc){ 66 return function(hint){ 67 68 hidePopover(); 69 70 // sigh. 71 previousHint = $(".CodeMirror-hint-active"); 72 73 var ctx, 74 hintObj, 75 prefixed, 76 val, 77 content = "", 78 i; 79 80 for(i = 0; i < ldKeywords.length; i++){ 81 if(ldKeywords[i].key === hint.text){ 82 hintObj = ldKeywords[i]; 83 } 84 } 85 86 if(!hintObj && doc && (ctx = doc["@context"])){ 87 prefixed = hint.text.split(":"); 88 89 90 if(ctx.hasOwnProperty(hint.text)){ 91 val = ctx[hint.text]; 92 if(prefixed.length === 2){ 93 // some kind of prefix? 94 hintObj = { 95 type: val["@type"] ? [val["@type"]] : undefined, 96 description: (ctx[prefixed[0]] || "") + prefixed[1] 97 }; 98 }else if(typeof val === "object"){ 99 // some complex thing? 100 hintObj = { 101 type: val["@type"] ? [val["@type"]] : undefined, 102 description: val["@id"] 103 }; 104 }else{ 105 // some kind of naked value? 106 hintObj = { 107 description: val 108 }; 109 } 110 }else if(ctx.hasOwnProperty(prefixed[0])){ 111 hintObj = { 112 description: (ctx[prefixed[0]] || "") + prefixed[1] 113 }; 114 } 115 } 116 117 if(!hintObj){ return; } 118 119 if(hintObj.description){ 120 content += '<p><em>' + 121 hintObj.description.replace(/<.*>/g, '') + 122 '</em></p>'; 123 } 124 125 if(hintObj.type && hintObj.type.length){ 126 content += "<p>Expects "; 127 for(i = 0; i < hintObj.type.length; i++){ 128 content += label(hintObj.type[i]); 129 } 130 content += "</p>"; 131 } 132 133 if(hintObj.enum && hintObj.enum.length){ 134 content += "<p>Can be "; 135 for(i = 0; i < hintObj.enum.length; i++){ 136 content += label(hintObj.enum[i]); 137 } 138 content += "</p>"; 139 } 140 141 if(hintObj.format){ 142 content += "<p>Format " + label(hintObj.format) + "</p>"; 143 } 144 145 previousHint.popover({ 146 content: content, 147 container: "body", 148 html: true 149 }); 150 previousHint.popover("show"); 151 }; 152 } 153 154 function label(value, cls){ 155 return '<span class="label ' + (cls || "") + '">' + 156 value.replace(/<.*>/g, '') + 157 '</span>'; 158 } 159 160 function findLdKeywords(schemata){ 161 var i, 162 def_key, 163 def, 164 prop_key, 165 prop; 166 // pull out the @ keywords 167 for(i = 0; i < schemata.length; i++){ 168 var schema = schemata[0]; 169 for(def_key in schema.definitions){ 170 def = schema.definitions[def_key]; 171 for(prop_key in def.properties){ 172 prop = def.properties[prop_key]; 173 if(prop_key.indexOf("@") === 0){ 174 ldKeywords.push({ 175 key: prop_key, 176 description: prop.description, 177 type: typeof prop.type === "string" ? 178 [prop.type] : (prop.type || []), 179 format: prop.format, 180 enum: prop.enum || [] 181 }); 182 } 183 } 184 } 185 } 186 } 187 188 CodeMirror.registerHelper("hint", "jsonld", function(editor, options){ 189 190 // Find the token at the cursor 191 var cur = editor.getCursor(), 192 token = getToken(editor, cur), 193 tprop = token, 194 195 // was this started by pressing "@" 196 isAt = options.isAt, 197 lastParsed = options.lastParsed, 198 199 schemata = typeof options.schemata === "function" ? 200 options.schemata() : 201 options.schemata, 202 203 word = token.string, 204 start = token.start, 205 end = token.end + -1 * (word.slice(-1) === '"'), 206 207 match,
208 stripped = false, 209 210 result; 211 212 if(!ldKeywords.length && schemata.length){ 213 findLdKeywords(schemata); 214 } 215 216 function suggest(suggestions){ 217 var hints = { 218 list: suggestions, 219 from: Pos(cur.line, start + 1), 220 to: Pos(cur.line, end) 221 }; 222 223 // various hint events 224 CodeMirror.on(hints, "select", showPopover(lastParsed)); 225 CodeMirror.on(hints, "close", hidePopover); 226 227 return hints; 228 } 229 230 token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; 231 232 function finish(word){ 233 // clean up words, move pointers 234 if(word.match(/^[\{\[]/)){ 235 // i just made an empty list and typed "@"... 236 word = ""; 237 start++; 238 stripped = true; 239 }else if(word.match(/^"/)){ 240 // i just started a quoted string... 241 word = word.replace(/(^"|"$)/g, ""); 242 stripped = true; 243 } 244 245 if(isAt){ 246 // this was started by pressing @.. 247 if(!~word.indexOf("@")){ 248 // and the user is expecting a @ 249 editor.replaceSelection("@", "end", "+input"); 250 }else if(!stripped){ 251 start--; 252 } 253 return suggest(keywordsLike(word.replace("@", ""))); 254 }else if(match = word.match(/^"?@(.*)/)){ 255 return suggest(keywordsLike(match[1])); 256 } 257 258 return suggest(contextLike(word, lastParsed).concat(keywordsLike(word))); 259 } 260 261 result = finish(word); 262 if(!result.list.length && word.indexOf(":") !== -1 && word.indexOf("://") === -1){ 263 // try again with the prefix 264 result = finish(word.split(":")[0]); 265 result.list.unshift({text: word.replace(/"/g, "")}); 266 } 267 return result; 268 }); 269}).call(this, CodeMirror, CodeMirror.Pos, $);
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.