-
Notifications
You must be signed in to change notification settings - Fork 0
/
lwp-example-complex.js.map
1 lines (1 loc) · 13.3 KB
/
lwp-example-complex.js.map
1
{"version":3,"sources":["lwp-example-complex.litcoffee"],"names":["isJustArithmetic","mightBeAName","setAppName","addHelpMenuSourceCodeLink","window","helpAboutText","groupTypes","name","text","tooltip","color","imageHTML","openImageHTML","closeImageHTML","tagContents","group","content","contentAsText","contentsChanged","firstTime","doNotEvaluateAgain","set","Background","addTask","result","safeResult","deleted","replace","tagMenuItems","onclick","alert","setContentAsText","contextMenuItems","split","test","registerFunction","e","whenToStop","Date","getTime","eval","error","i","len","word","words","length","toUpperCase"],"mappings":"AAeI,IAAAA,iBAAAC,aAAAC,WAAW,cAIXC,0BACI,iEAIJC,OAAOC,cACH,wLAUJD,OAAOE,aASHC,KAAO,cACPC,KAAO,oBACPC,QAAU,+BACVC,MAAQ,UACRC,UAAY,0CACZC,cAAgB,wCAChBC,eAAiB,wCAOjBC,YAAc,SAAEC,GACZ,IAAAC,EACA,OAAG,OADHA,EAAUD,EAAME,kBACAjB,iBAAiBgB,GAC7B,wBAEA,WAyBRE,gBAAkB,SAAEH,EAAOI,GAQvB,IAAGJ,EAAMK,0BAQTL,EAAMM,IAAI,kBAAmB,oCAI7BC,WAAWC,QAAQ,iBAAmBR,GAAS,SAAES,GAM7C,IAAAC,EAAA,IAAGV,EAAMW,SAAe,MAAAF,SAMxBC,GAAa,GAAGD,GAASG,QAAQ,KAAM,SACtCA,QAAQ,KAAM,QACdA,QAAQ,KAAM,QACdA,QAAQ,KAAM,UACdA,QAAQ,KAAM,UACfF,EAAa,0BAA4BA,EAAW,UACpDV,EAAMK,oBAAqB,EAC3BL,EAAMM,IAAI,kBAAmBI,GAC7BV,EAAMK,oBAAqB,OAUnCb,KAAO,QACPC,KAAO,iBACPC,QAAU,6BACVC,MAAQ,UACRC,UAAY,0CACZC,cAAgB,wCAChBC,eAAiB,wCAMjBC,YAAc,SAAEC,UAAWd,aAAac,EAAME,kBAM9CW,aAAe,SAAEb,WAMTP,KAAO,gBACPqB,QAAU,kBACNC,MAAM,iCACC7B,aAAac,EAAME,iBAAgB,kJAU9CT,KAAO,0BACPqB,QAAU,kBAAGd,EAAMgB,iBAAiB,mBAEpCvB,KAAO,8BACPqB,QAAU,kBAAGd,EAAMgB,iBAAiB,uBAS5CC,iBAAmB,SAAEjB,WAEbP,KAAO,0BACPqB,QAAU,kBACNC,MAAM,sBACAf,EAAME,gBAAP,OAA8B,0CAGvCT,KAAO,wBACPqB,QAAU,kBACNC,MAAM,oBACAf,EAAME,gBAAgBgB,MAAO,KAA9B,OAA2C,0DAchEjC,iBAAmB,SAAEQ,SAAU,oBAAmB0B,KAAK1B,IAwBvDc,WAAWa,iBAAiB,gBAAiB,SAAEpB,OAC3C,IAAAqB,EAAAZ,OAAAa,WACA,IADAA,YAAa,IAAMC,MAAOC,UAAY,KAChC,IAAMD,MAAOC,UAAYF,YAC3Bb,OAAA,WAAS,GAAG,MAAAT,MAAAP,OAAgBR,iBAAiBe,MAAMP,YAG/C,MAFA,WAAIgC,KAAKzB,MAAMP,MAAf,MAAAiC,UAA0BL,EAAAK,EAAO,OADrC,UAIJjB,SACFxB,iBAAmBA,mBAKrBC,aAAe,SAAEO,GACb,IAAAkC,EAAAC,EAAAC,EAAAC,EACA,GAAO,OADPA,EAAQrC,EAAKyB,MAAM,OACFY,EAAMC,OAAS,GAAqB,IAAhBD,EAAMC,OACvC,MAAO,sBACX,IAAAJ,EAAA,EAAAC,EAAAE,EAAAC,OAAAJ,EAAAC,EAAAD,IACI,GAAO,eAAA,IAAYE,EAAK,GAAGG,gBAAmBH,EAAK,GAC/C,MAAO,4BACf","file":"lwp-example-complex.js","sourcesContent":["\n# Lurch Web Platform, Second Example Application\n\n## Overview\n\nThis documentation assumes that you have seen [the simple example\napplication](https://github.com/lurchmath/lwp-example-simple). This app is\njust a few steps more complex than that one. Once you understand this\nexample, feel free to browse some of the other examples in [the Lurch\nProject's GitHub space](https://github.com/lurchmath).\n\n[A live version of this app is online here.](https://lurchmath.github.io/lwp-example-complex)\n\nSet the app name with the same function we used in the simple example app.\n\n setAppName 'ComplexApp'\n\nAdd a source code link to the help menu, as in the simple example app.\n\n addHelpMenuSourceCodeLink \\\n 'lwp-example-complex/blob/master/lwp-example-complex.litcoffee'\n\nWe also change the Help/About menu item to be specific to this demo app.\n\n window.helpAboutText =\n '<p>See the fully documented <a target=\"top\"\n href=\"https://github.com/lurchmath/lwp-example-complex/blob/master/lwp-example-complex.litcoffee\"\n >source code for this demo app</a>.</p>'\n\n## Define two group types\n\nAs in the simple example, we assign to a global variable, which is noticed\nby the LWP setup process and respected. This time, we define two group\ntypes.\n\n window.groupTypes = [\n\n### Computations\n\nThe first type is groups that perform simple arithmetic computations on\ntheir contents, decorating the ending grouper with the result. For\ninstance, a group containing 3+2 would have its ending grouper contain the\ntext \"=5.\"\n\n name : 'computation'\n text : 'Computation group'\n tooltip : 'Make selection a computation'\n color : '#996666'\n imageHTML : '<font color=\"#996666\"><b>[ ]</b></font>'\n openImageHTML : '<font color=\"#996666\"><b>[</b></font>'\n closeImageHTML : '<font color=\"#996666\"><b>]</b></font>'\n\nThe tag on a bubble will either classify it as an arithmetic expression or\nnot. This shows one example use of the bubble tag, as a status indicator.\nThe `isJustArithmetic` function is defined [at the end of this\nfile](#auxiliary-functions).\n\n tagContents : ( group ) ->\n content = group.contentAsText()\n if content? and isJustArithmetic content\n 'arithmetic expression'\n else\n 'unknown'\n\nWhenever the group's contents change, we must recompute their value, if the\ncontents are a valid arithmetic expression. Although such a task is nearly\ninstantaneous, this example app runs it in the background *and forces it to\ntake one second, as an example* of how a lengthy computation could be sent\nto a background thread. The background computation called \"do arithmetic\"\nis defined [at the end of this file](#auxiliary-functions).\n\nThe `Background.addTask` function enqueues a task to be done later. The\nparameters are\n 1. the name of the function to do (defined by a call to\n `Background.registerFunction`, as [below](#auxiliary-functions)),\n 1. the array of groups to pass as parameters, and\n 1. the callback to be called in this (main, UI) thread when the computation\n is complete.\n\nThere are situations in which that callback may never be called. If there\nis an error in your background processing code, the callback will not be\ncalled. If the user changes the contents of the group before the\ncomputation completes, the background process will be discarded and a new\none initiated because the old one has become irrelevant. In such a case,\nonly the callback from the second one will be called (assuming that it\ncompletes without error or early termination).\n\n contentsChanged : ( group, firstTime ) ->\n\nFirst, it may be that the contents changed merely because the computation\nended and we placed its result in the close grouper (as at the end of this\nfunction). That counts as a change to this group, but we would not want to\nrespond to that. As you can see at the end of this function, we mark such\nmoments with a flag `doNotEvaluateAgain`, and we check that flag here.\n\n if group.doNotEvaluateAgain then return\n\nWe begin by placing an ellipsis as the decoration at the end of the group,\nto show that computation is in progress. Again, the computations in this\napp do not *actually* take very long, but we have artificially extended them\nto take one second, just as a demonstration of what might happen in more\ncomputationally intensive contexts.\n\n group.set 'closeDecoration', '<font color=\"#999999\">...</font>'\n\nNow we enqueue the background task.\n\n Background.addTask 'do arithmetic', [ group ], ( result ) ->\n\nWe must always check in any callback whether the group we wish to modify\nstill exists in our document. (The user may delete it in the interim, and\nattempting to modify its contents would then cause errors.)\n\n if group.deleted or not result? then return\n\nWe can now change the decoration at the end of the group to indicate that we\nhave computed a value for the group, using an equals sign, and green text to\nindicate success.\n\n safeResult = \"#{result}\".replace /&/g, '&'\n .replace /</g, '<'\n .replace />/g, '>'\n .replace /\"/g, '"'\n .replace /'/g, '''\n safeResult = \"<font color=\\\"#009900\\\">=#{safeResult}</font>\"\n group.doNotEvaluateAgain = yes\n group.set 'closeDecoration', safeResult\n group.doNotEvaluateAgain = no\n\n### Groups with menus\n\nWe now define a second group type, one that doesn't compute anything\nautomatically, but that allows you to ask questions about it and perform\noperations on it with the context menu and/or the bubble tag menu. This is\nto demonstrate that multiple group types can exist within the same app.\n\n ,\n name : 'words'\n text : 'Group of words'\n tooltip : 'Make selection about words'\n color : '#669966'\n imageHTML : '<font color=\"#669966\"><b>( )</b></font>'\n openImageHTML : '<font color=\"#669966\"><b>(</b></font>'\n closeImageHTML : '<font color=\"#669966\"><b>)</b></font>'\n\nThe tag on a bubble will either classify the group as something that might\nbe a proper name, or something that probably isn't. The function\n`mightBeAName` is defined at the end of this file.\n\n tagContents : ( group ) -> mightBeAName group.contentAsText()\n\nWe now provide a small popup menu that appears when the user clicks the\ngroup's tag, and whose actions deal with that tag's content. It returns an\narray of menu items, each with text and an `onclick` handler.\n\n tagMenuItems : ( group ) ->\n [\n\nThe first menu item explains why the group was classified as it was on its\ntag.\n\n text : 'Why this tag?'\n onclick : ->\n alert \"This group was classified as\n '#{mightBeAName group.contentAsText()}' for the\n following reason:\\nText 'might be a name' if it has\n one to three words, all capitalized. Otherwise,\n it is 'probably not a name.'\"\n\nThe second and third items give the user the ability to change the group,\npopulating it with example text content that satisfies or does not satisfy\n(respectively, for the two menu items) the criteria for namehood.\n\n ,\n text : 'Change this into a name'\n onclick : -> group.setContentAsText 'Rufus Dimble'\n ,\n text : 'Change this into a non-name'\n onclick : -> group.setContentAsText 'corn on the cob'\n ]\n\nWe also provide a context menu that the user can bring up by right-clicking\nanywhere inside the group.\n\nThe two items on it count the numbers of letters or words in the group's\ninterior, reporting it in a popup dialog that the user must then dismiss.\n\n contextMenuItems : ( group ) ->\n [\n text : 'Count number of letters'\n onclick : ->\n alert \"Number of letters:\n #{group.contentAsText().length}\\n(includes spaces\n and punctuation)\"\n ,\n text : 'Count number of words'\n onclick : ->\n alert \"Number of words:\n #{group.contentAsText().split( ' ' ).length}\n \\n(counts any sequence of non-spaces as a word)\"\n ]\n ]\n\nThat completes the main part of the app. The remainder of this file is a\nfew auxiliary functions mentioned above, but not yet defined.\n\n## Auxiliary functions\n\nThe following function determines if a text string contains only numbers and\noperators appropriate for an arithmetic expression, and thus safe to pass\nto `eval()`.\n\n isJustArithmetic = ( text ) -> /^[.0-9+*/ ()-]+$/.test text\n\nHere we register the background function used by the testing routine above\nin `contentsChanged`. Although this could just call `eval` and be done, we\nplace it in a loop that forces the computation to last for one second (the\n1000 in the code is in milliseconds), to simulate a computation that takes a\nlong time, and thus needed to be moved into the background.\n\nBecause this routine will be run in a separate thread, it does not have\naccess to the same group object as in the main, UI thread. Rather, we get a\nsimplified copy of the group, which is an object containing the members\n`id`, `typeName`, `deleted`, `text`, `html`, `parent`, `children`, and\n`data`. These are not all documented here; see [the source code for the\nGroups plugin for\ndetails](https://github.com/lurchmath/lurch/blob/master/source/plugins/groupsplugin.litcoffee),\nin `Group.toJSON()`.\n\nNote that because this will be run in a background thread, we cannot make\nuse of any functions defined in the current namespace. In particular, we\nmust copy in the regular expression in `isJustArithmetic`, because it will\nnot be available in the thread in which this function will be run. This is\ndone in the second argument, which is a list of objects to be (deep) copied\ninto the background thread.\n\n Background.registerFunction 'do arithmetic', ( group ) ->\n whenToStop = ( new Date ).getTime() + 1000\n while ( new Date ).getTime() < whenToStop\n result = if group.text? and isJustArithmetic group.text\n try eval group.text catch e then '???'\n else\n '???'\n result\n , isJustArithmetic : isJustArithmetic\n\nWhat does it mean for something to be a name, or probably a name? Proper\nnames are three or fewer words, each of which is capitalized.\n\n mightBeAName = ( text ) ->\n words = text.split ' '\n if not words? or words.length > 3 or words.length is 0\n return 'probably not a name'\n for word in words\n if not word[0]? or word[0].toUpperCase() isnt word[0]\n return 'probably not a name'\n 'might be a name'\n"]}