From fcf9ac8e2b6d1a3eefc451b9424b37615f71799d Mon Sep 17 00:00:00 2001 From: Amanda Date: Fri, 19 Jun 2015 09:45:52 -0400 Subject: [PATCH 001/199] Have text appear when 2 or more lines of code --- content/src/controller.js | 9 +++++++++ content/src/debug.js | 1 + content/src/editor.less | 1 - content/src/view.js | 26 +++++++++++++++++++++++++- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/content/src/controller.js b/content/src/controller.js index 1ad3e3df..7a60315a 100644 --- a/content/src/controller.js +++ b/content/src/controller.js @@ -102,6 +102,7 @@ function logCodeEvent(action, filename, code, mode, lang) { // function modelatpos(pos) { return model.pane[paneatpos(pos)]; + } // @@ -435,6 +436,8 @@ view.on('changehtmlcss', function(pane) { view.on('run', runAction); +var times_run = 0; + function runAction() { var doc = view.getPaneEditorData(paneatpos('left')); if (!doc) { @@ -469,6 +472,11 @@ function runAction() { logCodeEvent('run', filename, newdata.data, view.getPaneEditorBlockMode(paneatpos('left')), view.getPaneEditorLanguage(paneatpos('left'))); + times_run++; + console.log("How many times it is running:", times_run); + if (times_run >= 1) { + view.create_some(); + } if (!specialowner()) { // Remember the most recently run program. cookie('recent', window.location.href, @@ -495,6 +503,7 @@ view.on('logout', function() { view.flashNotification('Logged out.'); }); + view.on('login', function() { if (specialowner()) { saveAction(false, 'Log in and save.', null); diff --git a/content/src/debug.js b/content/src/debug.js index f545c7a7..e45bde75 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -118,6 +118,7 @@ var debug = window.ide = { record.line = lineno; debugRecordsByDebugId[currentDebugId] = record; debugRecordsByLineNo[lineno] = record; + console.log(traceEvents.length); }, setSourceMap: function (map) { currentSourceMap = map; diff --git a/content/src/editor.less b/content/src/editor.less index d3362bc1..fca7faba 100644 --- a/content/src/editor.less +++ b/content/src/editor.less @@ -985,7 +985,6 @@ body#pencildoc #diigolet-csm { .hpanel:nth-of-type(1) { border-top: none } - .hoverlay { cursor: row-resize; position: fixed; diff --git a/content/src/view.js b/content/src/view.js index d8cc8605..f6bd7e53 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -143,6 +143,7 @@ window.pencilcode.view = { evalInRunningPane: evalInRunningPane, showProtractor: showProtractor, hideProtractor: hideProtractor, + create_some: create_some, setPrimaryFocus: setPrimaryFocus, // setPaneRunUrl: setPaneRunUrl, hideEditor: function(pane) { @@ -225,6 +226,29 @@ function publish(method, args, requestid){ function paneid(position) { return $('.' + position).find('.pane').attr('id'); } +//note: need to move. +var create_some_run = false; +function create_some(){ + var div = document.createElement('div'); + div.className = 'scrubber'; + div.innerHTML = "
Scrubbers are awesome
"; + div.style.top = "500px"; + // div.style.visibility = 'visible'; + div.style.position = 'absolute'; + div.style.left = "100px"; + div.style.top = "300px" + if (!create_some_run && $(".ace_gutter-cell").length >= 2){ + console.log("view is working"); + $(".hpanel").css({ height: "500px" }) + $("#bravo").append(div); + create_some_run = true; + } + if ($(".ace_gutter-cell").length <= 2 && create_some_run){ + $(".scrubber").remove(); + create_some_run = false; + } + +} function panepos(id) { return $('#' + id).closest('.panebox').attr('class').replace(/\s|panebox/g, ''); @@ -697,7 +721,7 @@ function showMiddleButton(which) { 'title="Restart program (Ctrl+Enter)">' + '
'; } else { - html = ''; } $('#middle').find('div').eq(0).html(html); From 91dc0b5bc8ee0bcc197b55f0b2c3b460236a4fd8 Mon Sep 17 00:00:00 2001 From: Amanda Date: Fri, 19 Jun 2015 16:17:41 -0400 Subject: [PATCH 002/199] Working on integrating slider library --- content/lib/jquery-ui.css | 1225 +++ content/lib/jquery-ui.js | 16617 ++++++++++++++++++++++++++++++++++++ content/src/jquery-ui.css | 1225 +++ content/src/jquery-ui.js | 16617 ++++++++++++++++++++++++++++++++++++ content/src/jquery.js | 9210 ++++++++++++++++++++ content/src/simple.html | 22 + content/src/untitled.html | 22 + content/src/view.js | 2 +- 8 files changed, 44939 insertions(+), 1 deletion(-) create mode 100755 content/lib/jquery-ui.css create mode 100755 content/lib/jquery-ui.js create mode 100755 content/src/jquery-ui.css create mode 100755 content/src/jquery-ui.js create mode 100644 content/src/jquery.js create mode 100644 content/src/simple.html create mode 100644 content/src/untitled.html diff --git a/content/lib/jquery-ui.css b/content/lib/jquery-ui.css new file mode 100755 index 00000000..0822f910 --- /dev/null +++ b/content/lib/jquery-ui.css @@ -0,0 +1,1225 @@ +/*! jQuery UI - v1.11.4 - 2015-06-19 +* http://jqueryui.com +* Includes: core.css, draggable.css, resizable.css, selectable.css, sortable.css, accordion.css, autocomplete.css, button.css, datepicker.css, dialog.css, menu.css, progressbar.css, selectmenu.css, slider.css, spinner.css, tabs.css, tooltip.css, theme.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=gloss_wave&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=highlight_soft&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=glass&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=diagonals_thick&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px +* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { + display: none; +} +.ui-helper-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} +.ui-helper-reset { + margin: 0; + padding: 0; + border: 0; + outline: 0; + line-height: 1.3; + text-decoration: none; + font-size: 100%; + list-style: none; +} +.ui-helper-clearfix:before, +.ui-helper-clearfix:after { + content: ""; + display: table; + border-collapse: collapse; +} +.ui-helper-clearfix:after { + clear: both; +} +.ui-helper-clearfix { + min-height: 0; /* support: IE7 */ +} +.ui-helper-zfix { + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; + opacity: 0; + filter:Alpha(Opacity=0); /* support: IE8 */ +} + +.ui-front { + z-index: 100; +} + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { + cursor: default !important; +} + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + display: block; + text-indent: -99999px; + overflow: hidden; + background-repeat: no-repeat; +} + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.ui-draggable-handle { + -ms-touch-action: none; + touch-action: none; +} +.ui-resizable { + position: relative; +} +.ui-resizable-handle { + position: absolute; + font-size: 0.1px; + display: block; + -ms-touch-action: none; + touch-action: none; +} +.ui-resizable-disabled .ui-resizable-handle, +.ui-resizable-autohide .ui-resizable-handle { + display: none; +} +.ui-resizable-n { + cursor: n-resize; + height: 7px; + width: 100%; + top: -5px; + left: 0; +} +.ui-resizable-s { + cursor: s-resize; + height: 7px; + width: 100%; + bottom: -5px; + left: 0; +} +.ui-resizable-e { + cursor: e-resize; + width: 7px; + right: -5px; + top: 0; + height: 100%; +} +.ui-resizable-w { + cursor: w-resize; + width: 7px; + left: -5px; + top: 0; + height: 100%; +} +.ui-resizable-se { + cursor: se-resize; + width: 12px; + height: 12px; + right: 1px; + bottom: 1px; +} +.ui-resizable-sw { + cursor: sw-resize; + width: 9px; + height: 9px; + left: -5px; + bottom: -5px; +} +.ui-resizable-nw { + cursor: nw-resize; + width: 9px; + height: 9px; + left: -5px; + top: -5px; +} +.ui-resizable-ne { + cursor: ne-resize; + width: 9px; + height: 9px; + right: -5px; + top: -5px; +} +.ui-selectable { + -ms-touch-action: none; + touch-action: none; +} +.ui-selectable-helper { + position: absolute; + z-index: 100; + border: 1px dotted black; +} +.ui-sortable-handle { + -ms-touch-action: none; + touch-action: none; +} +.ui-accordion .ui-accordion-header { + display: block; + cursor: pointer; + position: relative; + margin: 2px 0 0 0; + padding: .5em .5em .5em .7em; + min-height: 0; /* support: IE7 */ + font-size: 100%; +} +.ui-accordion .ui-accordion-icons { + padding-left: 2.2em; +} +.ui-accordion .ui-accordion-icons .ui-accordion-icons { + padding-left: 2.2em; +} +.ui-accordion .ui-accordion-header .ui-accordion-header-icon { + position: absolute; + left: .5em; + top: 50%; + margin-top: -8px; +} +.ui-accordion .ui-accordion-content { + padding: 1em 2.2em; + border-top: 0; + overflow: auto; +} +.ui-autocomplete { + position: absolute; + top: 0; + left: 0; + cursor: default; +} +.ui-button { + display: inline-block; + position: relative; + padding: 0; + line-height: normal; + margin-right: .1em; + cursor: pointer; + vertical-align: middle; + text-align: center; + overflow: visible; /* removes extra width in IE */ +} +.ui-button, +.ui-button:link, +.ui-button:visited, +.ui-button:hover, +.ui-button:active { + text-decoration: none; +} +/* to make room for the icon, a width needs to be set here */ +.ui-button-icon-only { + width: 2.2em; +} +/* button elements seem to need a little more width */ +button.ui-button-icon-only { + width: 2.4em; +} +.ui-button-icons-only { + width: 3.4em; +} +button.ui-button-icons-only { + width: 3.7em; +} + +/* button text element */ +.ui-button .ui-button-text { + display: block; + line-height: normal; +} +.ui-button-text-only .ui-button-text { + padding: .4em 1em; +} +.ui-button-icon-only .ui-button-text, +.ui-button-icons-only .ui-button-text { + padding: .4em; + text-indent: -9999999px; +} +.ui-button-text-icon-primary .ui-button-text, +.ui-button-text-icons .ui-button-text { + padding: .4em 1em .4em 2.1em; +} +.ui-button-text-icon-secondary .ui-button-text, +.ui-button-text-icons .ui-button-text { + padding: .4em 2.1em .4em 1em; +} +.ui-button-text-icons .ui-button-text { + padding-left: 2.1em; + padding-right: 2.1em; +} +/* no icon support for input elements, provide padding by default */ +input.ui-button { + padding: .4em 1em; +} + +/* button icon element(s) */ +.ui-button-icon-only .ui-icon, +.ui-button-text-icon-primary .ui-icon, +.ui-button-text-icon-secondary .ui-icon, +.ui-button-text-icons .ui-icon, +.ui-button-icons-only .ui-icon { + position: absolute; + top: 50%; + margin-top: -8px; +} +.ui-button-icon-only .ui-icon { + left: 50%; + margin-left: -8px; +} +.ui-button-text-icon-primary .ui-button-icon-primary, +.ui-button-text-icons .ui-button-icon-primary, +.ui-button-icons-only .ui-button-icon-primary { + left: .5em; +} +.ui-button-text-icon-secondary .ui-button-icon-secondary, +.ui-button-text-icons .ui-button-icon-secondary, +.ui-button-icons-only .ui-button-icon-secondary { + right: .5em; +} + +/* button sets */ +.ui-buttonset { + margin-right: 7px; +} +.ui-buttonset .ui-button { + margin-left: 0; + margin-right: -.3em; +} + +/* workarounds */ +/* reset extra padding in Firefox, see h5bp.com/l */ +input.ui-button::-moz-focus-inner, +button.ui-button::-moz-focus-inner { + border: 0; + padding: 0; +} +.ui-datepicker { + width: 17em; + padding: .2em .2em 0; + display: none; +} +.ui-datepicker .ui-datepicker-header { + position: relative; + padding: .2em 0; +} +.ui-datepicker .ui-datepicker-prev, +.ui-datepicker .ui-datepicker-next { + position: absolute; + top: 2px; + width: 1.8em; + height: 1.8em; +} +.ui-datepicker .ui-datepicker-prev-hover, +.ui-datepicker .ui-datepicker-next-hover { + top: 1px; +} +.ui-datepicker .ui-datepicker-prev { + left: 2px; +} +.ui-datepicker .ui-datepicker-next { + right: 2px; +} +.ui-datepicker .ui-datepicker-prev-hover { + left: 1px; +} +.ui-datepicker .ui-datepicker-next-hover { + right: 1px; +} +.ui-datepicker .ui-datepicker-prev span, +.ui-datepicker .ui-datepicker-next span { + display: block; + position: absolute; + left: 50%; + margin-left: -8px; + top: 50%; + margin-top: -8px; +} +.ui-datepicker .ui-datepicker-title { + margin: 0 2.3em; + line-height: 1.8em; + text-align: center; +} +.ui-datepicker .ui-datepicker-title select { + font-size: 1em; + margin: 1px 0; +} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { + width: 45%; +} +.ui-datepicker table { + width: 100%; + font-size: .9em; + border-collapse: collapse; + margin: 0 0 .4em; +} +.ui-datepicker th { + padding: .7em .3em; + text-align: center; + font-weight: bold; + border: 0; +} +.ui-datepicker td { + border: 0; + padding: 1px; +} +.ui-datepicker td span, +.ui-datepicker td a { + display: block; + padding: .2em; + text-align: right; + text-decoration: none; +} +.ui-datepicker .ui-datepicker-buttonpane { + background-image: none; + margin: .7em 0 0 0; + padding: 0 .2em; + border-left: 0; + border-right: 0; + border-bottom: 0; +} +.ui-datepicker .ui-datepicker-buttonpane button { + float: right; + margin: .5em .2em .4em; + cursor: pointer; + padding: .2em .6em .3em .6em; + width: auto; + overflow: visible; +} +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { + float: left; +} + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { + width: auto; +} +.ui-datepicker-multi .ui-datepicker-group { + float: left; +} +.ui-datepicker-multi .ui-datepicker-group table { + width: 95%; + margin: 0 auto .4em; +} +.ui-datepicker-multi-2 .ui-datepicker-group { + width: 50%; +} +.ui-datepicker-multi-3 .ui-datepicker-group { + width: 33.3%; +} +.ui-datepicker-multi-4 .ui-datepicker-group { + width: 25%; +} +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { + border-left-width: 0; +} +.ui-datepicker-multi .ui-datepicker-buttonpane { + clear: left; +} +.ui-datepicker-row-break { + clear: both; + width: 100%; + font-size: 0; +} + +/* RTL support */ +.ui-datepicker-rtl { + direction: rtl; +} +.ui-datepicker-rtl .ui-datepicker-prev { + right: 2px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next { + left: 2px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-prev:hover { + right: 1px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next:hover { + left: 1px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane { + clear: right; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button { + float: left; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current, +.ui-datepicker-rtl .ui-datepicker-group { + float: right; +} +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { + border-right-width: 0; + border-left-width: 1px; +} +.ui-dialog { + overflow: hidden; + position: absolute; + top: 0; + left: 0; + padding: .2em; + outline: 0; +} +.ui-dialog .ui-dialog-titlebar { + padding: .4em 1em; + position: relative; +} +.ui-dialog .ui-dialog-title { + float: left; + margin: .1em 0; + white-space: nowrap; + width: 90%; + overflow: hidden; + text-overflow: ellipsis; +} +.ui-dialog .ui-dialog-titlebar-close { + position: absolute; + right: .3em; + top: 50%; + width: 20px; + margin: -10px 0 0 0; + padding: 1px; + height: 20px; +} +.ui-dialog .ui-dialog-content { + position: relative; + border: 0; + padding: .5em 1em; + background: none; + overflow: auto; +} +.ui-dialog .ui-dialog-buttonpane { + text-align: left; + border-width: 1px 0 0 0; + background-image: none; + margin-top: .5em; + padding: .3em 1em .5em .4em; +} +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { + float: right; +} +.ui-dialog .ui-dialog-buttonpane button { + margin: .5em .4em .5em 0; + cursor: pointer; +} +.ui-dialog .ui-resizable-se { + width: 12px; + height: 12px; + right: -5px; + bottom: -5px; + background-position: 16px 16px; +} +.ui-draggable .ui-dialog-titlebar { + cursor: move; +} +.ui-menu { + list-style: none; + padding: 0; + margin: 0; + display: block; + outline: none; +} +.ui-menu .ui-menu { + position: absolute; +} +.ui-menu .ui-menu-item { + position: relative; + margin: 0; + padding: 3px 1em 3px .4em; + cursor: pointer; + min-height: 0; /* support: IE7 */ + /* support: IE10, see #8844 */ + list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"); +} +.ui-menu .ui-menu-divider { + margin: 5px 0; + height: 0; + font-size: 0; + line-height: 0; + border-width: 1px 0 0 0; +} +.ui-menu .ui-state-focus, +.ui-menu .ui-state-active { + margin: -1px; +} + +/* icon support */ +.ui-menu-icons { + position: relative; +} +.ui-menu-icons .ui-menu-item { + padding-left: 2em; +} + +/* left-aligned */ +.ui-menu .ui-icon { + position: absolute; + top: 0; + bottom: 0; + left: .2em; + margin: auto 0; +} + +/* right-aligned */ +.ui-menu .ui-menu-icon { + left: auto; + right: 0; +} +.ui-progressbar { + height: 2em; + text-align: left; + overflow: hidden; +} +.ui-progressbar .ui-progressbar-value { + margin: -1px; + height: 100%; +} +.ui-progressbar .ui-progressbar-overlay { + background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw=="); + height: 100%; + filter: alpha(opacity=25); /* support: IE8 */ + opacity: 0.25; +} +.ui-progressbar-indeterminate .ui-progressbar-value { + background-image: none; +} +.ui-selectmenu-menu { + padding: 0; + margin: 0; + position: absolute; + top: 0; + left: 0; + display: none; +} +.ui-selectmenu-menu .ui-menu { + overflow: auto; + /* Support: IE7 */ + overflow-x: hidden; + padding-bottom: 1px; +} +.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup { + font-size: 1em; + font-weight: bold; + line-height: 1.5; + padding: 2px 0.4em; + margin: 0.5em 0 0 0; + height: auto; + border: 0; +} +.ui-selectmenu-open { + display: block; +} +.ui-selectmenu-button { + display: inline-block; + overflow: hidden; + position: relative; + text-decoration: none; + cursor: pointer; +} +.ui-selectmenu-button span.ui-icon { + right: 0.5em; + left: auto; + margin-top: -8px; + position: absolute; + top: 50%; +} +.ui-selectmenu-button span.ui-selectmenu-text { + text-align: left; + padding: 0.4em 2.1em 0.4em 1em; + display: block; + line-height: 1.4; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.ui-slider { + position: relative; + text-align: left; +} +.ui-slider .ui-slider-handle { + position: absolute; + z-index: 2; + width: 1.2em; + height: 1.2em; + cursor: default; + -ms-touch-action: none; + touch-action: none; +} +.ui-slider .ui-slider-range { + position: absolute; + z-index: 1; + font-size: .7em; + display: block; + border: 0; + background-position: 0 0; +} + +/* support: IE8 - See #6727 */ +.ui-slider.ui-state-disabled .ui-slider-handle, +.ui-slider.ui-state-disabled .ui-slider-range { + filter: inherit; +} + +.ui-slider-horizontal { + height: .8em; +} +.ui-slider-horizontal .ui-slider-handle { + top: -.3em; + margin-left: -.6em; +} +.ui-slider-horizontal .ui-slider-range { + top: 0; + height: 100%; +} +.ui-slider-horizontal .ui-slider-range-min { + left: 0; +} +.ui-slider-horizontal .ui-slider-range-max { + right: 0; +} + +.ui-slider-vertical { + width: .8em; + height: 100px; +} +.ui-slider-vertical .ui-slider-handle { + left: -.3em; + margin-left: 0; + margin-bottom: -.6em; +} +.ui-slider-vertical .ui-slider-range { + left: 0; + width: 100%; +} +.ui-slider-vertical .ui-slider-range-min { + bottom: 0; +} +.ui-slider-vertical .ui-slider-range-max { + top: 0; +} +.ui-spinner { + position: relative; + display: inline-block; + overflow: hidden; + padding: 0; + vertical-align: middle; +} +.ui-spinner-input { + border: none; + background: none; + color: inherit; + padding: 0; + margin: .2em 0; + vertical-align: middle; + margin-left: .4em; + margin-right: 22px; +} +.ui-spinner-button { + width: 16px; + height: 50%; + font-size: .5em; + padding: 0; + margin: 0; + text-align: center; + position: absolute; + cursor: default; + display: block; + overflow: hidden; + right: 0; +} +/* more specificity required here to override default borders */ +.ui-spinner a.ui-spinner-button { + border-top: none; + border-bottom: none; + border-right: none; +} +/* vertically center icon */ +.ui-spinner .ui-icon { + position: absolute; + margin-top: -8px; + top: 50%; + left: 0; +} +.ui-spinner-up { + top: 0; +} +.ui-spinner-down { + bottom: 0; +} + +/* TR overrides */ +.ui-spinner .ui-icon-triangle-1-s { + /* need to fix icons sprite */ + background-position: -65px -16px; +} +.ui-tabs { + position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ + padding: .2em; +} +.ui-tabs .ui-tabs-nav { + margin: 0; + padding: .2em .2em 0; +} +.ui-tabs .ui-tabs-nav li { + list-style: none; + float: left; + position: relative; + top: 0; + margin: 1px .2em 0 0; + border-bottom-width: 0; + padding: 0; + white-space: nowrap; +} +.ui-tabs .ui-tabs-nav .ui-tabs-anchor { + float: left; + padding: .5em 1em; + text-decoration: none; +} +.ui-tabs .ui-tabs-nav li.ui-tabs-active { + margin-bottom: -1px; + padding-bottom: 1px; +} +.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor, +.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor, +.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor { + cursor: text; +} +.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor { + cursor: pointer; +} +.ui-tabs .ui-tabs-panel { + display: block; + border-width: 0; + padding: 1em 1.4em; + background: none; +} +.ui-tooltip { + padding: 8px; + position: absolute; + z-index: 9999; + max-width: 300px; + -webkit-box-shadow: 0 0 5px #aaa; + box-shadow: 0 0 5px #aaa; +} +body .ui-tooltip { + border-width: 2px; +} + +/* Component containers +----------------------------------*/ +.ui-widget { + font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif; + font-size: 1.1em; +} +.ui-widget .ui-widget { + font-size: 1em; +} +.ui-widget input, +.ui-widget select, +.ui-widget textarea, +.ui-widget button { + font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif; + font-size: 1em; +} +.ui-widget-content { + border: 1px solid #dddddd; + background: #eeeeee url("images/ui-bg_highlight-soft_100_eeeeee_1x100.png") 50% top repeat-x; + color: #333333; +} +.ui-widget-content a { + color: #333333; +} +.ui-widget-header { + border: 1px solid #e78f08; + background: #f6a828 url("images/ui-bg_gloss-wave_35_f6a828_500x100.png") 50% 50% repeat-x; + color: #ffffff; + font-weight: bold; +} +.ui-widget-header a { + color: #ffffff; +} + +/* Interaction states +----------------------------------*/ +.ui-state-default, +.ui-widget-content .ui-state-default, +.ui-widget-header .ui-state-default { + border: 1px solid #cccccc; + background: #f6f6f6 url("images/ui-bg_glass_100_f6f6f6_1x400.png") 50% 50% repeat-x; + font-weight: bold; + color: #1c94c4; +} +.ui-state-default a, +.ui-state-default a:link, +.ui-state-default a:visited { + color: #1c94c4; + text-decoration: none; +} +.ui-state-hover, +.ui-widget-content .ui-state-hover, +.ui-widget-header .ui-state-hover, +.ui-state-focus, +.ui-widget-content .ui-state-focus, +.ui-widget-header .ui-state-focus { + border: 1px solid #fbcb09; + background: #fdf5ce url("images/ui-bg_glass_100_fdf5ce_1x400.png") 50% 50% repeat-x; + font-weight: bold; + color: #c77405; +} +.ui-state-hover a, +.ui-state-hover a:hover, +.ui-state-hover a:link, +.ui-state-hover a:visited, +.ui-state-focus a, +.ui-state-focus a:hover, +.ui-state-focus a:link, +.ui-state-focus a:visited { + color: #c77405; + text-decoration: none; +} +.ui-state-active, +.ui-widget-content .ui-state-active, +.ui-widget-header .ui-state-active { + border: 1px solid #fbd850; + background: #ffffff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x; + font-weight: bold; + color: #eb8f00; +} +.ui-state-active a, +.ui-state-active a:link, +.ui-state-active a:visited { + color: #eb8f00; + text-decoration: none; +} + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, +.ui-widget-content .ui-state-highlight, +.ui-widget-header .ui-state-highlight { + border: 1px solid #fed22f; + background: #ffe45c url("images/ui-bg_highlight-soft_75_ffe45c_1x100.png") 50% top repeat-x; + color: #363636; +} +.ui-state-highlight a, +.ui-widget-content .ui-state-highlight a, +.ui-widget-header .ui-state-highlight a { + color: #363636; +} +.ui-state-error, +.ui-widget-content .ui-state-error, +.ui-widget-header .ui-state-error { + border: 1px solid #cd0a0a; + background: #b81900 url("images/ui-bg_diagonals-thick_18_b81900_40x40.png") 50% 50% repeat; + color: #ffffff; +} +.ui-state-error a, +.ui-widget-content .ui-state-error a, +.ui-widget-header .ui-state-error a { + color: #ffffff; +} +.ui-state-error-text, +.ui-widget-content .ui-state-error-text, +.ui-widget-header .ui-state-error-text { + color: #ffffff; +} +.ui-priority-primary, +.ui-widget-content .ui-priority-primary, +.ui-widget-header .ui-priority-primary { + font-weight: bold; +} +.ui-priority-secondary, +.ui-widget-content .ui-priority-secondary, +.ui-widget-header .ui-priority-secondary { + opacity: .7; + filter:Alpha(Opacity=70); /* support: IE8 */ + font-weight: normal; +} +.ui-state-disabled, +.ui-widget-content .ui-state-disabled, +.ui-widget-header .ui-state-disabled { + opacity: .35; + filter:Alpha(Opacity=35); /* support: IE8 */ + background-image: none; +} +.ui-state-disabled .ui-icon { + filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */ +} + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + width: 16px; + height: 16px; +} +.ui-icon, +.ui-widget-content .ui-icon { + background-image: url("images/ui-icons_222222_256x240.png"); +} +.ui-widget-header .ui-icon { + background-image: url("images/ui-icons_ffffff_256x240.png"); +} +.ui-state-default .ui-icon { + background-image: url("images/ui-icons_ef8c08_256x240.png"); +} +.ui-state-hover .ui-icon, +.ui-state-focus .ui-icon { + background-image: url("images/ui-icons_ef8c08_256x240.png"); +} +.ui-state-active .ui-icon { + background-image: url("images/ui-icons_ef8c08_256x240.png"); +} +.ui-state-highlight .ui-icon { + background-image: url("images/ui-icons_228ef1_256x240.png"); +} +.ui-state-error .ui-icon, +.ui-state-error-text .ui-icon { + background-image: url("images/ui-icons_ffd27a_256x240.png"); +} + +/* positioning */ +.ui-icon-blank { background-position: 16px 16px; } +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-on { background-position: -96px -144px; } +.ui-icon-radio-off { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, +.ui-corner-top, +.ui-corner-left, +.ui-corner-tl { + border-top-left-radius: 4px; +} +.ui-corner-all, +.ui-corner-top, +.ui-corner-right, +.ui-corner-tr { + border-top-right-radius: 4px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-left, +.ui-corner-bl { + border-bottom-left-radius: 4px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-right, +.ui-corner-br { + border-bottom-right-radius: 4px; +} + +/* Overlays */ +.ui-widget-overlay { + background: #666666 url("images/ui-bg_diagonals-thick_20_666666_40x40.png") 50% 50% repeat; + opacity: .5; + filter: Alpha(Opacity=50); /* support: IE8 */ +} +.ui-widget-shadow { + margin: -5px 0 0 -5px; + padding: 5px; + background: #000000 url("images/ui-bg_flat_10_000000_40x100.png") 50% 50% repeat-x; + opacity: .2; + filter: Alpha(Opacity=20); /* support: IE8 */ + border-radius: 5px; +} diff --git a/content/lib/jquery-ui.js b/content/lib/jquery-ui.js new file mode 100755 index 00000000..0a2c0441 --- /dev/null +++ b/content/lib/jquery-ui.js @@ -0,0 +1,16617 @@ +/*! jQuery UI - v1.11.4 - 2015-06-14 +* http://jqueryui.com +* Includes: core.js, widget.js, mouse.js, position.js, draggable.js, droppable.js, resizable.js, selectable.js, sortable.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, menu.js, progressbar.js, selectmenu.js, slider.js, spinner.js, tabs.js, tooltip.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js +* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define([ "jquery" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +}(function( $ ) { +/*! + * jQuery UI Core 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/category/ui-core/ + */ + + +// $.ui might exist from components with no dependencies, e.g., $.ui.position +$.ui = $.ui || {}; + +$.extend( $.ui, { + version: "1.11.4", + + keyCode: { + BACKSPACE: 8, + COMMA: 188, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + LEFT: 37, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SPACE: 32, + TAB: 9, + UP: 38 + } +}); + +// plugins +$.fn.extend({ + scrollParent: function( includeHidden ) { + var position = this.css( "position" ), + excludeStaticParent = position === "absolute", + overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, + scrollParent = this.parents().filter( function() { + var parent = $( this ); + if ( excludeStaticParent && parent.css( "position" ) === "static" ) { + return false; + } + return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) ); + }).eq( 0 ); + + return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent; + }, + + uniqueId: (function() { + var uuid = 0; + + return function() { + return this.each(function() { + if ( !this.id ) { + this.id = "ui-id-" + ( ++uuid ); + } + }); + }; + })(), + + removeUniqueId: function() { + return this.each(function() { + if ( /^ui-id-\d+$/.test( this.id ) ) { + $( this ).removeAttr( "id" ); + } + }); + } +}); + +// selectors +function focusable( element, isTabIndexNotNaN ) { + var map, mapName, img, + nodeName = element.nodeName.toLowerCase(); + if ( "area" === nodeName ) { + map = element.parentNode; + mapName = map.name; + if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { + return false; + } + img = $( "img[usemap='#" + mapName + "']" )[ 0 ]; + return !!img && visible( img ); + } + return ( /^(input|select|textarea|button|object)$/.test( nodeName ) ? + !element.disabled : + "a" === nodeName ? + element.href || isTabIndexNotNaN : + isTabIndexNotNaN) && + // the element and all of its ancestors must be visible + visible( element ); +} + +function visible( element ) { + return $.expr.filters.visible( element ) && + !$( element ).parents().addBack().filter(function() { + return $.css( this, "visibility" ) === "hidden"; + }).length; +} + +$.extend( $.expr[ ":" ], { + data: $.expr.createPseudo ? + $.expr.createPseudo(function( dataName ) { + return function( elem ) { + return !!$.data( elem, dataName ); + }; + }) : + // support: jQuery <1.8 + function( elem, i, match ) { + return !!$.data( elem, match[ 3 ] ); + }, + + focusable: function( element ) { + return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); + }, + + tabbable: function( element ) { + var tabIndex = $.attr( element, "tabindex" ), + isTabIndexNaN = isNaN( tabIndex ); + return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); + } +}); + +// support: jQuery <1.8 +if ( !$( "" ).outerWidth( 1 ).jquery ) { + $.each( [ "Width", "Height" ], function( i, name ) { + var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], + type = name.toLowerCase(), + orig = { + innerWidth: $.fn.innerWidth, + innerHeight: $.fn.innerHeight, + outerWidth: $.fn.outerWidth, + outerHeight: $.fn.outerHeight + }; + + function reduce( elem, size, border, margin ) { + $.each( side, function() { + size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; + if ( border ) { + size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; + } + if ( margin ) { + size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; + } + }); + return size; + } + + $.fn[ "inner" + name ] = function( size ) { + if ( size === undefined ) { + return orig[ "inner" + name ].call( this ); + } + + return this.each(function() { + $( this ).css( type, reduce( this, size ) + "px" ); + }); + }; + + $.fn[ "outer" + name] = function( size, margin ) { + if ( typeof size !== "number" ) { + return orig[ "outer" + name ].call( this, size ); + } + + return this.each(function() { + $( this).css( type, reduce( this, size, true, margin ) + "px" ); + }); + }; + }); +} + +// support: jQuery <1.8 +if ( !$.fn.addBack ) { + $.fn.addBack = function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + }; +} + +// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) +if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { + $.fn.removeData = (function( removeData ) { + return function( key ) { + if ( arguments.length ) { + return removeData.call( this, $.camelCase( key ) ); + } else { + return removeData.call( this ); + } + }; + })( $.fn.removeData ); +} + +// deprecated +$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); + +$.fn.extend({ + focus: (function( orig ) { + return function( delay, fn ) { + return typeof delay === "number" ? + this.each(function() { + var elem = this; + setTimeout(function() { + $( elem ).focus(); + if ( fn ) { + fn.call( elem ); + } + }, delay ); + }) : + orig.apply( this, arguments ); + }; + })( $.fn.focus ), + + disableSelection: (function() { + var eventType = "onselectstart" in document.createElement( "div" ) ? + "selectstart" : + "mousedown"; + + return function() { + return this.bind( eventType + ".ui-disableSelection", function( event ) { + event.preventDefault(); + }); + }; + })(), + + enableSelection: function() { + return this.unbind( ".ui-disableSelection" ); + }, + + zIndex: function( zIndex ) { + if ( zIndex !== undefined ) { + return this.css( "zIndex", zIndex ); + } + + if ( this.length ) { + var elem = $( this[ 0 ] ), position, value; + while ( elem.length && elem[ 0 ] !== document ) { + // Ignore z-index if position is set to a value where z-index is ignored by the browser + // This makes behavior of this function consistent across browsers + // WebKit always returns auto if the element is positioned + position = elem.css( "position" ); + if ( position === "absolute" || position === "relative" || position === "fixed" ) { + // IE returns 0 when zIndex is not specified + // other browsers return a string + // we ignore the case of nested elements with an explicit value of 0 + //
+ value = parseInt( elem.css( "zIndex" ), 10 ); + if ( !isNaN( value ) && value !== 0 ) { + return value; + } + } + elem = elem.parent(); + } + } + + return 0; + } +}); + +// $.ui.plugin is deprecated. Use $.widget() extensions instead. +$.ui.plugin = { + add: function( module, option, set ) { + var i, + proto = $.ui[ module ].prototype; + for ( i in set ) { + proto.plugins[ i ] = proto.plugins[ i ] || []; + proto.plugins[ i ].push( [ option, set[ i ] ] ); + } + }, + call: function( instance, name, args, allowDisconnected ) { + var i, + set = instance.plugins[ name ]; + + if ( !set ) { + return; + } + + if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) { + return; + } + + for ( i = 0; i < set.length; i++ ) { + if ( instance.options[ set[ i ][ 0 ] ] ) { + set[ i ][ 1 ].apply( instance.element, args ); + } + } + } +}; + + +/*! + * jQuery UI Widget 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/jQuery.widget/ + */ + + +var widget_uuid = 0, + widget_slice = Array.prototype.slice; + +$.cleanData = (function( orig ) { + return function( elems ) { + var events, elem, i; + for ( i = 0; (elem = elems[i]) != null; i++ ) { + try { + + // Only trigger remove when necessary to save time + events = $._data( elem, "events" ); + if ( events && events.remove ) { + $( elem ).triggerHandler( "remove" ); + } + + // http://bugs.jquery.com/ticket/8235 + } catch ( e ) {} + } + orig( elems ); + }; +})( $.cleanData ); + +$.widget = function( name, base, prototype ) { + var fullName, existingConstructor, constructor, basePrototype, + // proxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + proxiedPrototype = {}, + namespace = name.split( "." )[ 0 ]; + + name = name.split( "." )[ 1 ]; + fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + // create selector for plugin + $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { + return !!$.data( elem, fullName ); + }; + + $[ namespace ] = $[ namespace ] || {}; + existingConstructor = $[ namespace ][ name ]; + constructor = $[ namespace ][ name ] = function( options, element ) { + // allow instantiation without "new" keyword + if ( !this._createWidget ) { + return new constructor( options, element ); + } + + // allow instantiation without initializing for simple inheritance + // must use "new" keyword (the code above always passes args) + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + // extend with the existing constructor to carry over any static properties + $.extend( constructor, existingConstructor, { + version: prototype.version, + // copy the object used to create the prototype in case we need to + // redefine the widget later + _proto: $.extend( {}, prototype ), + // track widgets that inherit from this widget in case this widget is + // redefined after a widget inherits from it + _childConstructors: [] + }); + + basePrototype = new base(); + // we need to make the options hash a property directly on the new instance + // otherwise we'll modify the options hash on the prototype that we're + // inheriting from + basePrototype.options = $.widget.extend( {}, basePrototype.options ); + $.each( prototype, function( prop, value ) { + if ( !$.isFunction( value ) ) { + proxiedPrototype[ prop ] = value; + return; + } + proxiedPrototype[ prop ] = (function() { + var _super = function() { + return base.prototype[ prop ].apply( this, arguments ); + }, + _superApply = function( args ) { + return base.prototype[ prop ].apply( this, args ); + }; + return function() { + var __super = this._super, + __superApply = this._superApply, + returnValue; + + this._super = _super; + this._superApply = _superApply; + + returnValue = value.apply( this, arguments ); + + this._super = __super; + this._superApply = __superApply; + + return returnValue; + }; + })(); + }); + constructor.prototype = $.widget.extend( basePrototype, { + // TODO: remove support for widgetEventPrefix + // always use the name + a colon as the prefix, e.g., draggable:start + // don't prefix for widgets that aren't DOM-based + widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name + }, proxiedPrototype, { + constructor: constructor, + namespace: namespace, + widgetName: name, + widgetFullName: fullName + }); + + // If this widget is being redefined then we need to find all widgets that + // are inheriting from it and redefine all of them so that they inherit from + // the new version of this widget. We're essentially trying to replace one + // level in the prototype chain. + if ( existingConstructor ) { + $.each( existingConstructor._childConstructors, function( i, child ) { + var childPrototype = child.prototype; + + // redefine the child widget using the same prototype that was + // originally used, but inherit from the new version of the base + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); + }); + // remove the list of existing child constructors from the old constructor + // so the old child constructors can be garbage collected + delete existingConstructor._childConstructors; + } else { + base._childConstructors.push( constructor ); + } + + $.widget.bridge( name, constructor ); + + return constructor; +}; + +$.widget.extend = function( target ) { + var input = widget_slice.call( arguments, 1 ), + inputIndex = 0, + inputLength = input.length, + key, + value; + for ( ; inputIndex < inputLength; inputIndex++ ) { + for ( key in input[ inputIndex ] ) { + value = input[ inputIndex ][ key ]; + if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { + // Clone objects + if ( $.isPlainObject( value ) ) { + target[ key ] = $.isPlainObject( target[ key ] ) ? + $.widget.extend( {}, target[ key ], value ) : + // Don't extend strings, arrays, etc. with objects + $.widget.extend( {}, value ); + // Copy everything else by reference + } else { + target[ key ] = value; + } + } + } + } + return target; +}; + +$.widget.bridge = function( name, object ) { + var fullName = object.prototype.widgetFullName || name; + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string", + args = widget_slice.call( arguments, 1 ), + returnValue = this; + + if ( isMethodCall ) { + this.each(function() { + var methodValue, + instance = $.data( this, fullName ); + if ( options === "instance" ) { + returnValue = instance; + return false; + } + if ( !instance ) { + return $.error( "cannot call methods on " + name + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for " + name + " widget instance" ); + } + methodValue = instance[ options ].apply( instance, args ); + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; + return false; + } + }); + } else { + + // Allow multiple hashes to be passed on init + if ( args.length ) { + options = $.widget.extend.apply( null, [ options ].concat(args) ); + } + + this.each(function() { + var instance = $.data( this, fullName ); + if ( instance ) { + instance.option( options || {} ); + if ( instance._init ) { + instance._init(); + } + } else { + $.data( this, fullName, new object( options, this ) ); + } + }); + } + + return returnValue; + }; +}; + +$.Widget = function( /* options, element */ ) {}; +$.Widget._childConstructors = []; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + defaultElement: "
", + options: { + disabled: false, + + // callbacks + create: null + }, + _createWidget: function( options, element ) { + element = $( element || this.defaultElement || this )[ 0 ]; + this.element = $( element ); + this.uuid = widget_uuid++; + this.eventNamespace = "." + this.widgetName + this.uuid; + + this.bindings = $(); + this.hoverable = $(); + this.focusable = $(); + + if ( element !== this ) { + $.data( element, this.widgetFullName, this ); + this._on( true, this.element, { + remove: function( event ) { + if ( event.target === element ) { + this.destroy(); + } + } + }); + this.document = $( element.style ? + // element within the document + element.ownerDocument : + // element is window or document + element.document || element ); + this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); + } + + this.options = $.widget.extend( {}, + this.options, + this._getCreateOptions(), + options ); + + this._create(); + this._trigger( "create", null, this._getCreateEventData() ); + this._init(); + }, + _getCreateOptions: $.noop, + _getCreateEventData: $.noop, + _create: $.noop, + _init: $.noop, + + destroy: function() { + this._destroy(); + // we can probably remove the unbind calls in 2.0 + // all event bindings should go through this._on() + this.element + .unbind( this.eventNamespace ) + .removeData( this.widgetFullName ) + // support: jquery <1.6.3 + // http://bugs.jquery.com/ticket/9413 + .removeData( $.camelCase( this.widgetFullName ) ); + this.widget() + .unbind( this.eventNamespace ) + .removeAttr( "aria-disabled" ) + .removeClass( + this.widgetFullName + "-disabled " + + "ui-state-disabled" ); + + // clean up events and states + this.bindings.unbind( this.eventNamespace ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + }, + _destroy: $.noop, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key, + parts, + curOption, + i; + + if ( arguments.length === 0 ) { + // don't return a reference to the internal hash + return $.widget.extend( {}, this.options ); + } + + if ( typeof key === "string" ) { + // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } + options = {}; + parts = key.split( "." ); + key = parts.shift(); + if ( parts.length ) { + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); + for ( i = 0; i < parts.length - 1; i++ ) { + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; + curOption = curOption[ parts[ i ] ]; + } + key = parts.pop(); + if ( arguments.length === 1 ) { + return curOption[ key ] === undefined ? null : curOption[ key ]; + } + curOption[ key ] = value; + } else { + if ( arguments.length === 1 ) { + return this.options[ key ] === undefined ? null : this.options[ key ]; + } + options[ key ] = value; + } + } + + this._setOptions( options ); + + return this; + }, + _setOptions: function( options ) { + var key; + + for ( key in options ) { + this._setOption( key, options[ key ] ); + } + + return this; + }, + _setOption: function( key, value ) { + this.options[ key ] = value; + + if ( key === "disabled" ) { + this.widget() + .toggleClass( this.widgetFullName + "-disabled", !!value ); + + // If the widget is becoming disabled, then nothing is interactive + if ( value ) { + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + } + } + + return this; + }, + + enable: function() { + return this._setOptions({ disabled: false }); + }, + disable: function() { + return this._setOptions({ disabled: true }); + }, + + _on: function( suppressDisabledCheck, element, handlers ) { + var delegateElement, + instance = this; + + // no suppressDisabledCheck flag, shuffle arguments + if ( typeof suppressDisabledCheck !== "boolean" ) { + handlers = element; + element = suppressDisabledCheck; + suppressDisabledCheck = false; + } + + // no element argument, shuffle and use this.element + if ( !handlers ) { + handlers = element; + element = this.element; + delegateElement = this.widget(); + } else { + element = delegateElement = $( element ); + this.bindings = this.bindings.add( element ); + } + + $.each( handlers, function( event, handler ) { + function handlerProxy() { + // allow widgets to customize the disabled handling + // - disabled as an array instead of boolean + // - disabled class as method for disabling individual parts + if ( !suppressDisabledCheck && + ( instance.options.disabled === true || + $( this ).hasClass( "ui-state-disabled" ) ) ) { + return; + } + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + + // copy the guid so direct unbinding works + if ( typeof handler !== "string" ) { + handlerProxy.guid = handler.guid = + handler.guid || handlerProxy.guid || $.guid++; + } + + var match = event.match( /^([\w:-]*)\s*(.*)$/ ), + eventName = match[1] + instance.eventNamespace, + selector = match[2]; + if ( selector ) { + delegateElement.delegate( selector, eventName, handlerProxy ); + } else { + element.bind( eventName, handlerProxy ); + } + }); + }, + + _off: function( element, eventName ) { + eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + + this.eventNamespace; + element.unbind( eventName ).undelegate( eventName ); + + // Clear the stack to avoid memory leaks (#10056) + this.bindings = $( this.bindings.not( element ).get() ); + this.focusable = $( this.focusable.not( element ).get() ); + this.hoverable = $( this.hoverable.not( element ).get() ); + }, + + _delay: function( handler, delay ) { + function handlerProxy() { + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + var instance = this; + return setTimeout( handlerProxy, delay || 0 ); + }, + + _hoverable: function( element ) { + this.hoverable = this.hoverable.add( element ); + this._on( element, { + mouseenter: function( event ) { + $( event.currentTarget ).addClass( "ui-state-hover" ); + }, + mouseleave: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-hover" ); + } + }); + }, + + _focusable: function( element ) { + this.focusable = this.focusable.add( element ); + this._on( element, { + focusin: function( event ) { + $( event.currentTarget ).addClass( "ui-state-focus" ); + }, + focusout: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-focus" ); + } + }); + }, + + _trigger: function( type, event, data ) { + var prop, orig, + callback = this.options[ type ]; + + data = data || {}; + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + // the original event may come from any element + // so we need to reset the target on the new event + event.target = this.element[ 0 ]; + + // copy original event properties over to the new event + orig = event.originalEvent; + if ( orig ) { + for ( prop in orig ) { + if ( !( prop in event ) ) { + event[ prop ] = orig[ prop ]; + } + } + } + + this.element.trigger( event, data ); + return !( $.isFunction( callback ) && + callback.apply( this.element[0], [ event ].concat( data ) ) === false || + event.isDefaultPrevented() ); + } +}; + +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { + if ( typeof options === "string" ) { + options = { effect: options }; + } + var hasOptions, + effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + options = options || {}; + if ( typeof options === "number" ) { + options = { duration: options }; + } + hasOptions = !$.isEmptyObject( options ); + options.complete = callback; + if ( options.delay ) { + element.delay( options.delay ); + } + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { + element[ method ]( options ); + } else if ( effectName !== method && element[ effectName ] ) { + element[ effectName ]( options.duration, options.easing, callback ); + } else { + element.queue(function( next ) { + $( this )[ method ](); + if ( callback ) { + callback.call( element[ 0 ] ); + } + next(); + }); + } + }; +}); + +var widget = $.widget; + + +/*! + * jQuery UI Mouse 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/mouse/ + */ + + +var mouseHandled = false; +$( document ).mouseup( function() { + mouseHandled = false; +}); + +var mouse = $.widget("ui.mouse", { + version: "1.11.4", + options: { + cancel: "input,textarea,button,select,option", + distance: 1, + delay: 0 + }, + _mouseInit: function() { + var that = this; + + this.element + .bind("mousedown." + this.widgetName, function(event) { + return that._mouseDown(event); + }) + .bind("click." + this.widgetName, function(event) { + if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { + $.removeData(event.target, that.widgetName + ".preventClickEvent"); + event.stopImmediatePropagation(); + return false; + } + }); + + this.started = false; + }, + + // TODO: make sure destroying one instance of mouse doesn't mess with + // other instances of mouse + _mouseDestroy: function() { + this.element.unbind("." + this.widgetName); + if ( this._mouseMoveDelegate ) { + this.document + .unbind("mousemove." + this.widgetName, this._mouseMoveDelegate) + .unbind("mouseup." + this.widgetName, this._mouseUpDelegate); + } + }, + + _mouseDown: function(event) { + // don't let more than one widget handle mouseStart + if ( mouseHandled ) { + return; + } + + this._mouseMoved = false; + + // we may have missed mouseup (out of window) + (this._mouseStarted && this._mouseUp(event)); + + this._mouseDownEvent = event; + + var that = this, + btnIsLeft = (event.which === 1), + // event.target.nodeName works around a bug in IE 8 with + // disabled inputs (#7620) + elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); + if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { + return true; + } + + this.mouseDelayMet = !this.options.delay; + if (!this.mouseDelayMet) { + this._mouseDelayTimer = setTimeout(function() { + that.mouseDelayMet = true; + }, this.options.delay); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = (this._mouseStart(event) !== false); + if (!this._mouseStarted) { + event.preventDefault(); + return true; + } + } + + // Click event may never have fired (Gecko & Opera) + if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { + $.removeData(event.target, this.widgetName + ".preventClickEvent"); + } + + // these delegates are required to keep context + this._mouseMoveDelegate = function(event) { + return that._mouseMove(event); + }; + this._mouseUpDelegate = function(event) { + return that._mouseUp(event); + }; + + this.document + .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate ) + .bind( "mouseup." + this.widgetName, this._mouseUpDelegate ); + + event.preventDefault(); + + mouseHandled = true; + return true; + }, + + _mouseMove: function(event) { + // Only check for mouseups outside the document if you've moved inside the document + // at least once. This prevents the firing of mouseup in the case of IE<9, which will + // fire a mousemove event if content is placed under the cursor. See #7778 + // Support: IE <9 + if ( this._mouseMoved ) { + // IE mouseup check - mouseup happened when mouse was out of window + if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { + return this._mouseUp(event); + + // Iframe mouseup check - mouseup occurred in another document + } else if ( !event.which ) { + return this._mouseUp( event ); + } + } + + if ( event.which || event.button ) { + this._mouseMoved = true; + } + + if (this._mouseStarted) { + this._mouseDrag(event); + return event.preventDefault(); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = + (this._mouseStart(this._mouseDownEvent, event) !== false); + (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); + } + + return !this._mouseStarted; + }, + + _mouseUp: function(event) { + this.document + .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate ) + .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate ); + + if (this._mouseStarted) { + this._mouseStarted = false; + + if (event.target === this._mouseDownEvent.target) { + $.data(event.target, this.widgetName + ".preventClickEvent", true); + } + + this._mouseStop(event); + } + + mouseHandled = false; + return false; + }, + + _mouseDistanceMet: function(event) { + return (Math.max( + Math.abs(this._mouseDownEvent.pageX - event.pageX), + Math.abs(this._mouseDownEvent.pageY - event.pageY) + ) >= this.options.distance + ); + }, + + _mouseDelayMet: function(/* event */) { + return this.mouseDelayMet; + }, + + // These are placeholder methods, to be overriden by extending plugin + _mouseStart: function(/* event */) {}, + _mouseDrag: function(/* event */) {}, + _mouseStop: function(/* event */) {}, + _mouseCapture: function(/* event */) { return true; } +}); + + +/*! + * jQuery UI Position 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/position/ + */ + +(function() { + +$.ui = $.ui || {}; + +var cachedScrollbarWidth, supportsOffsetFractions, + max = Math.max, + abs = Math.abs, + round = Math.round, + rhorizontal = /left|center|right/, + rvertical = /top|center|bottom/, + roffset = /[\+\-]\d+(\.[\d]+)?%?/, + rposition = /^\w+/, + rpercent = /%$/, + _position = $.fn.position; + +function getOffsets( offsets, width, height ) { + return [ + parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), + parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) + ]; +} + +function parseCss( element, property ) { + return parseInt( $.css( element, property ), 10 ) || 0; +} + +function getDimensions( elem ) { + var raw = elem[0]; + if ( raw.nodeType === 9 ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: 0, left: 0 } + }; + } + if ( $.isWindow( raw ) ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: elem.scrollTop(), left: elem.scrollLeft() } + }; + } + if ( raw.preventDefault ) { + return { + width: 0, + height: 0, + offset: { top: raw.pageY, left: raw.pageX } + }; + } + return { + width: elem.outerWidth(), + height: elem.outerHeight(), + offset: elem.offset() + }; +} + +$.position = { + scrollbarWidth: function() { + if ( cachedScrollbarWidth !== undefined ) { + return cachedScrollbarWidth; + } + var w1, w2, + div = $( "
" ), + innerDiv = div.children()[0]; + + $( "body" ).append( div ); + w1 = innerDiv.offsetWidth; + div.css( "overflow", "scroll" ); + + w2 = innerDiv.offsetWidth; + + if ( w1 === w2 ) { + w2 = div[0].clientWidth; + } + + div.remove(); + + return (cachedScrollbarWidth = w1 - w2); + }, + getScrollInfo: function( within ) { + var overflowX = within.isWindow || within.isDocument ? "" : + within.element.css( "overflow-x" ), + overflowY = within.isWindow || within.isDocument ? "" : + within.element.css( "overflow-y" ), + hasOverflowX = overflowX === "scroll" || + ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), + hasOverflowY = overflowY === "scroll" || + ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); + return { + width: hasOverflowY ? $.position.scrollbarWidth() : 0, + height: hasOverflowX ? $.position.scrollbarWidth() : 0 + }; + }, + getWithinInfo: function( element ) { + var withinElement = $( element || window ), + isWindow = $.isWindow( withinElement[0] ), + isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9; + return { + element: withinElement, + isWindow: isWindow, + isDocument: isDocument, + offset: withinElement.offset() || { left: 0, top: 0 }, + scrollLeft: withinElement.scrollLeft(), + scrollTop: withinElement.scrollTop(), + + // support: jQuery 1.6.x + // jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows + width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(), + height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight() + }; + } +}; + +$.fn.position = function( options ) { + if ( !options || !options.of ) { + return _position.apply( this, arguments ); + } + + // make a copy, we don't want to modify arguments + options = $.extend( {}, options ); + + var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, + target = $( options.of ), + within = $.position.getWithinInfo( options.within ), + scrollInfo = $.position.getScrollInfo( within ), + collision = ( options.collision || "flip" ).split( " " ), + offsets = {}; + + dimensions = getDimensions( target ); + if ( target[0].preventDefault ) { + // force left top to allow flipping + options.at = "left top"; + } + targetWidth = dimensions.width; + targetHeight = dimensions.height; + targetOffset = dimensions.offset; + // clone to reuse original targetOffset later + basePosition = $.extend( {}, targetOffset ); + + // force my and at to have valid horizontal and vertical positions + // if a value is missing or invalid, it will be converted to center + $.each( [ "my", "at" ], function() { + var pos = ( options[ this ] || "" ).split( " " ), + horizontalOffset, + verticalOffset; + + if ( pos.length === 1) { + pos = rhorizontal.test( pos[ 0 ] ) ? + pos.concat( [ "center" ] ) : + rvertical.test( pos[ 0 ] ) ? + [ "center" ].concat( pos ) : + [ "center", "center" ]; + } + pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; + pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; + + // calculate offsets + horizontalOffset = roffset.exec( pos[ 0 ] ); + verticalOffset = roffset.exec( pos[ 1 ] ); + offsets[ this ] = [ + horizontalOffset ? horizontalOffset[ 0 ] : 0, + verticalOffset ? verticalOffset[ 0 ] : 0 + ]; + + // reduce to just the positions without the offsets + options[ this ] = [ + rposition.exec( pos[ 0 ] )[ 0 ], + rposition.exec( pos[ 1 ] )[ 0 ] + ]; + }); + + // normalize collision option + if ( collision.length === 1 ) { + collision[ 1 ] = collision[ 0 ]; + } + + if ( options.at[ 0 ] === "right" ) { + basePosition.left += targetWidth; + } else if ( options.at[ 0 ] === "center" ) { + basePosition.left += targetWidth / 2; + } + + if ( options.at[ 1 ] === "bottom" ) { + basePosition.top += targetHeight; + } else if ( options.at[ 1 ] === "center" ) { + basePosition.top += targetHeight / 2; + } + + atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); + basePosition.left += atOffset[ 0 ]; + basePosition.top += atOffset[ 1 ]; + + return this.each(function() { + var collisionPosition, using, + elem = $( this ), + elemWidth = elem.outerWidth(), + elemHeight = elem.outerHeight(), + marginLeft = parseCss( this, "marginLeft" ), + marginTop = parseCss( this, "marginTop" ), + collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, + collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, + position = $.extend( {}, basePosition ), + myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); + + if ( options.my[ 0 ] === "right" ) { + position.left -= elemWidth; + } else if ( options.my[ 0 ] === "center" ) { + position.left -= elemWidth / 2; + } + + if ( options.my[ 1 ] === "bottom" ) { + position.top -= elemHeight; + } else if ( options.my[ 1 ] === "center" ) { + position.top -= elemHeight / 2; + } + + position.left += myOffset[ 0 ]; + position.top += myOffset[ 1 ]; + + // if the browser doesn't support fractions, then round for consistent results + if ( !supportsOffsetFractions ) { + position.left = round( position.left ); + position.top = round( position.top ); + } + + collisionPosition = { + marginLeft: marginLeft, + marginTop: marginTop + }; + + $.each( [ "left", "top" ], function( i, dir ) { + if ( $.ui.position[ collision[ i ] ] ) { + $.ui.position[ collision[ i ] ][ dir ]( position, { + targetWidth: targetWidth, + targetHeight: targetHeight, + elemWidth: elemWidth, + elemHeight: elemHeight, + collisionPosition: collisionPosition, + collisionWidth: collisionWidth, + collisionHeight: collisionHeight, + offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], + my: options.my, + at: options.at, + within: within, + elem: elem + }); + } + }); + + if ( options.using ) { + // adds feedback as second argument to using callback, if present + using = function( props ) { + var left = targetOffset.left - position.left, + right = left + targetWidth - elemWidth, + top = targetOffset.top - position.top, + bottom = top + targetHeight - elemHeight, + feedback = { + target: { + element: target, + left: targetOffset.left, + top: targetOffset.top, + width: targetWidth, + height: targetHeight + }, + element: { + element: elem, + left: position.left, + top: position.top, + width: elemWidth, + height: elemHeight + }, + horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", + vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" + }; + if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { + feedback.horizontal = "center"; + } + if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { + feedback.vertical = "middle"; + } + if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { + feedback.important = "horizontal"; + } else { + feedback.important = "vertical"; + } + options.using.call( this, props, feedback ); + }; + } + + elem.offset( $.extend( position, { using: using } ) ); + }); +}; + +$.ui.position = { + fit: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, + outerWidth = within.width, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = withinOffset - collisionPosLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, + newOverRight; + + // element is wider than within + if ( data.collisionWidth > outerWidth ) { + // element is initially over the left side of within + if ( overLeft > 0 && overRight <= 0 ) { + newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; + position.left += overLeft - newOverRight; + // element is initially over right side of within + } else if ( overRight > 0 && overLeft <= 0 ) { + position.left = withinOffset; + // element is initially over both left and right sides of within + } else { + if ( overLeft > overRight ) { + position.left = withinOffset + outerWidth - data.collisionWidth; + } else { + position.left = withinOffset; + } + } + // too far left -> align with left edge + } else if ( overLeft > 0 ) { + position.left += overLeft; + // too far right -> align with right edge + } else if ( overRight > 0 ) { + position.left -= overRight; + // adjust based on position and margin + } else { + position.left = max( position.left - collisionPosLeft, position.left ); + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollTop : within.offset.top, + outerHeight = data.within.height, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = withinOffset - collisionPosTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, + newOverBottom; + + // element is taller than within + if ( data.collisionHeight > outerHeight ) { + // element is initially over the top of within + if ( overTop > 0 && overBottom <= 0 ) { + newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; + position.top += overTop - newOverBottom; + // element is initially over bottom of within + } else if ( overBottom > 0 && overTop <= 0 ) { + position.top = withinOffset; + // element is initially over both top and bottom of within + } else { + if ( overTop > overBottom ) { + position.top = withinOffset + outerHeight - data.collisionHeight; + } else { + position.top = withinOffset; + } + } + // too far up -> align with top + } else if ( overTop > 0 ) { + position.top += overTop; + // too far down -> align with bottom edge + } else if ( overBottom > 0 ) { + position.top -= overBottom; + // adjust based on position and margin + } else { + position.top = max( position.top - collisionPosTop, position.top ); + } + } + }, + flip: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.offset.left + within.scrollLeft, + outerWidth = within.width, + offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = collisionPosLeft - offsetLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, + myOffset = data.my[ 0 ] === "left" ? + -data.elemWidth : + data.my[ 0 ] === "right" ? + data.elemWidth : + 0, + atOffset = data.at[ 0 ] === "left" ? + data.targetWidth : + data.at[ 0 ] === "right" ? + -data.targetWidth : + 0, + offset = -2 * data.offset[ 0 ], + newOverRight, + newOverLeft; + + if ( overLeft < 0 ) { + newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; + if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { + position.left += myOffset + atOffset + offset; + } + } else if ( overRight > 0 ) { + newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; + if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { + position.left += myOffset + atOffset + offset; + } + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.offset.top + within.scrollTop, + outerHeight = within.height, + offsetTop = within.isWindow ? within.scrollTop : within.offset.top, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = collisionPosTop - offsetTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, + top = data.my[ 1 ] === "top", + myOffset = top ? + -data.elemHeight : + data.my[ 1 ] === "bottom" ? + data.elemHeight : + 0, + atOffset = data.at[ 1 ] === "top" ? + data.targetHeight : + data.at[ 1 ] === "bottom" ? + -data.targetHeight : + 0, + offset = -2 * data.offset[ 1 ], + newOverTop, + newOverBottom; + if ( overTop < 0 ) { + newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; + if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { + position.top += myOffset + atOffset + offset; + } + } else if ( overBottom > 0 ) { + newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; + if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { + position.top += myOffset + atOffset + offset; + } + } + } + }, + flipfit: { + left: function() { + $.ui.position.flip.left.apply( this, arguments ); + $.ui.position.fit.left.apply( this, arguments ); + }, + top: function() { + $.ui.position.flip.top.apply( this, arguments ); + $.ui.position.fit.top.apply( this, arguments ); + } + } +}; + +// fraction support test +(function() { + var testElement, testElementParent, testElementStyle, offsetLeft, i, + body = document.getElementsByTagName( "body" )[ 0 ], + div = document.createElement( "div" ); + + //Create a "fake body" for testing based on method used in jQuery.support + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0, + background: "none" + }; + if ( body ) { + $.extend( testElementStyle, { + position: "absolute", + left: "-1000px", + top: "-1000px" + }); + } + for ( i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || document.documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); + + div.style.cssText = "position: absolute; left: 10.7432222px;"; + + offsetLeft = $( div ).offset().left; + supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11; + + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); +})(); + +})(); + +var position = $.ui.position; + + +/*! + * jQuery UI Draggable 1.11.4 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/draggable/ + */ + + +$.widget("ui.draggable", $.ui.mouse, { + version: "1.11.4", + widgetEventPrefix: "drag", + options: { + addClasses: true, + appendTo: "parent", + axis: false, + connectToSortable: false, + containment: false, + cursor: "auto", + cursorAt: false, + grid: false, + handle: false, + helper: "original", + iframeFix: false, + opacity: false, + refreshPositions: false, + revert: false, + revertDuration: 500, + scope: "default", + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + snap: false, + snapMode: "both", + snapTolerance: 20, + stack: false, + zIndex: false, + + // callbacks + drag: null, + start: null, + stop: null + }, + _create: function() { + + if ( this.options.helper === "original" ) { + this._setPositionRelative(); + } + if (this.options.addClasses){ + this.element.addClass("ui-draggable"); + } + if (this.options.disabled){ + this.element.addClass("ui-draggable-disabled"); + } + this._setHandleClassName(); + + this._mouseInit(); + }, + + _setOption: function( key, value ) { + this._super( key, value ); + if ( key === "handle" ) { + this._removeHandleClassName(); + this._setHandleClassName(); + } + }, + + _destroy: function() { + if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) { + this.destroyOnClear = true; + return; + } + this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); + this._removeHandleClassName(); + this._mouseDestroy(); + }, + + _mouseCapture: function(event) { + var o = this.options; + + this._blurActiveElement( event ); + + // among others, prevent a drag on a resizable-handle + if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) { + return false; + } + + //Quit if we're not on a valid handle + this.handle = this._getHandle(event); + if (!this.handle) { + return false; + } + + this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix ); + + return true; + + }, + + _blockFrames: function( selector ) { + this.iframeBlocks = this.document.find( selector ).map(function() { + var iframe = $( this ); + + return $( "
" ) + .css( "position", "absolute" ) + .appendTo( iframe.parent() ) + .outerWidth( iframe.outerWidth() ) + .outerHeight( iframe.outerHeight() ) + .offset( iframe.offset() )[ 0 ]; + }); + }, + + _unblockFrames: function() { + if ( this.iframeBlocks ) { + this.iframeBlocks.remove(); + delete this.iframeBlocks; + } + }, + + _blurActiveElement: function( event ) { + var document = this.document[ 0 ]; + + // Only need to blur if the event occurred on the draggable itself, see #10527 + if ( !this.handleElement.is( event.target ) ) { + return; + } + + // support: IE9 + // IE9 throws an "Unspecified error" accessing document.activeElement from an
+
guide
diff --git a/content/src/thumbnail.js b/content/src/thumbnail.js new file mode 100644 index 00000000..4f207410 --- /dev/null +++ b/content/src/thumbnail.js @@ -0,0 +1,90 @@ +define([ + 'html2canvas' +], function( + html2canvas +) { + var THUMBNAIL_SIZE = 128; + + // Public functions + var thumbnail = { + generateThumbnailDataUrl: function(iframe) { + return new Promise(function(resolve, reject) { + // Get the canvas inside the iframe. + var innerDoc = iframe.contentDocument || iframe.contentWindow.document; + var turtlefield = innerDoc.getElementsByClassName('turtlefield')[1]; + if (turtlefield) { + html2canvas(turtlefield, { onrendered: onRendered }); + } else { + html2canvas(innerDoc.body, { onrendered: onRendered }); + } + function onRendered(canvas) { + resolve(getImageDataUrl(canvas, getImageInfo(canvas))); + } + }); + }, + getImageInfo: getImageInfo + } + + // Private functions + function getImageInfo(canvas) { + var w = canvas.width; + var h = canvas.height; + var ctx = canvas.getContext('2d'); + var imageData = ctx.getImageData(0, 0, w, h); + + // Initialize the coordinates for the image region, + // topLeft is initialized to bottom right, + // and bottomRight is initialized to top left. + var topLeft = { x: h, y: w }; + var bottomRight = { x: 0, y: 0 }; + + // Iterate through all the points to find the "interesting" region. + var x, y, index; + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + // Every pixel takes up 4 slots in the array, contains R, G, B, A. + index = (y * w + x) * 4; + // Thus `index + 3` is the index of the Alpha value. + if (imageData.data[index + 3] > 0) { + if (x < topLeft.x) { + topLeft.x = x; + } + if (x > bottomRight.x) { + bottomRight.x = x; + } + if (y < topLeft.y) { + topLeft.y = y; + } + if (y > bottomRight.y) { + bottomRight.y = y; + } + } + } + } + + // Calculate the actual image size. + var imageWidth = bottomRight.x - topLeft.x + 1; + var imageHeight = bottomRight.y - topLeft.y + 1; + + + return { width: imageWidth, height: imageHeight, data: imageData} + } + + function getImageDataUrl(canvas, imageInfo) { + // Draw the cropped image in a temp canvas and scale it down. + var tempCanvas = document.createElement('canvas'); + var tempCanvasCtx = tempCanvas.getContext('2d'); + tempCanvas.width = THUMBNAIL_SIZE; + tempCanvas.height = THUMBNAIL_SIZE; + tempCanvasCtx.drawImage(canvas, // Src canvas. + imageInfo.x, imageInfo.y, // Src coordinates. + imageInfo.size, imageInfo.size, // Src coordinates. + 0, 0, // Dest coordinates. + THUMBNAIL_SIZE, THUMBNAIL_SIZE); // Dest size. + + // Convert the temp canvas to data url and return. + return tempCanvas.toDataURL(); + } + + return thumbnail; +}); \ No newline at end of file diff --git a/content/src/view.js b/content/src/view.js index 6808858b..c1794ce3 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -236,7 +236,7 @@ function paneid(position) { //note: need to move. var create_some_run = false; var pictures = []; -function create_some(traceevents, loop){ +function create_some(traceevents, loop, screenshots){ var present_line = 0; var current_value = 0; var div = document.createElement('div'); @@ -246,6 +246,7 @@ function create_some(traceevents, loop){ /* div.style.top = "300px"; */ // div.style.width = "300px"; + if (!create_some_run && traceevents.length >= 2 && loop){ // $(".hpanel").css({ height: "500px" }) // $("#bravo").append(div); @@ -259,7 +260,7 @@ function create_some(traceevents, loop){ // range: "min", smooth: false, slide: function(event, ui){ - $("#sliderinfo").val(ui.value); + console.log(screenshots[ui.value].data); var prevno = traceevents[present_line].location.first_line; clearPaneEditorLine(paneid('left'), prevno, 'debugtrace'); current_value = ui.value; diff --git a/html2canvas.js b/html2canvas.js new file mode 100644 index 00000000..87926361 --- /dev/null +++ b/html2canvas.js @@ -0,0 +1,3375 @@ +/* + html2canvas 0.5.0-alpha1 + Copyright (c) 2015 Niklas von Hertzen + + Released under MIT License +*/ + +(function(window, document, exports, global, define, undefined){ + +/*! + * @overview es6-promise - a tiny implementation of Promises/A+. + * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) + * @license Licensed under MIT license + * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE + * @version 2.0.1 + */ + +(function(){function r(a,b){n[l]=a;n[l+1]=b;l+=2;2===l&&A()}function s(a){return"function"===typeof a}function F(){return function(){process.nextTick(t)}}function G(){var a=0,b=new B(t),c=document.createTextNode("");b.observe(c,{characterData:!0});return function(){c.data=a=++a%2}}function H(){var a=new MessageChannel;a.port1.onmessage=t;return function(){a.port2.postMessage(0)}}function I(){return function(){setTimeout(t,1)}}function t(){for(var a=0;a= 0x80 (not a basic code point)', + 'invalid-input': 'Invalid input' + }, + + /** Convenience shortcuts */ + baseMinusTMin = base - tMin, + floor = Math.floor, + stringFromCharCode = String.fromCharCode, + + /** Temporary variable */ + key; + + /*--------------------------------------------------------------------------*/ + + /** + * A generic error utility function. + * @private + * @param {String} type The error type. + * @returns {Error} Throws a `RangeError` with the applicable error message. + */ + function error(type) { + throw RangeError(errors[type]); + } + + /** + * A generic `Array#map` utility function. + * @private + * @param {Array} array The array to iterate over. + * @param {Function} callback The function that gets called for every array + * item. + * @returns {Array} A new array of values returned by the callback function. + */ + function map(array, fn) { + var length = array.length; + var result = []; + while (length--) { + result[length] = fn(array[length]); + } + return result; + } + + /** + * A simple `Array#map`-like wrapper to work with domain name strings or email + * addresses. + * @private + * @param {String} domain The domain name or email address. + * @param {Function} callback The function that gets called for every + * character. + * @returns {Array} A new string of characters returned by the callback + * function. + */ + function mapDomain(string, fn) { + var parts = string.split('@'); + var result = ''; + if (parts.length > 1) { + // In email addresses, only the domain name should be punycoded. Leave + // the local part (i.e. everything up to `@`) intact. + result = parts[0] + '@'; + string = parts[1]; + } + var labels = string.split(regexSeparators); + var encoded = map(labels, fn).join('.'); + return result + encoded; + } + + /** + * Creates an array containing the numeric code points of each Unicode + * character in the string. While JavaScript uses UCS-2 internally, + * this function will convert a pair of surrogate halves (each of which + * UCS-2 exposes as separate characters) into a single code point, + * matching UTF-16. + * @see `punycode.ucs2.encode` + * @see + * @memberOf punycode.ucs2 + * @name decode + * @param {String} string The Unicode input string (UCS-2). + * @returns {Array} The new array of code points. + */ + function ucs2decode(string) { + var output = [], + counter = 0, + length = string.length, + value, + extra; + while (counter < length) { + value = string.charCodeAt(counter++); + if (value >= 0xD800 && value <= 0xDBFF && counter < length) { + // high surrogate, and there is a next character + extra = string.charCodeAt(counter++); + if ((extra & 0xFC00) == 0xDC00) { // low surrogate + output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); + } else { + // unmatched surrogate; only append this code unit, in case the next + // code unit is the high surrogate of a surrogate pair + output.push(value); + counter--; + } + } else { + output.push(value); + } + } + return output; + } + + /** + * Creates a string based on an array of numeric code points. + * @see `punycode.ucs2.decode` + * @memberOf punycode.ucs2 + * @name encode + * @param {Array} codePoints The array of numeric code points. + * @returns {String} The new Unicode string (UCS-2). + */ + function ucs2encode(array) { + return map(array, function(value) { + var output = ''; + if (value > 0xFFFF) { + value -= 0x10000; + output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); + value = 0xDC00 | value & 0x3FF; + } + output += stringFromCharCode(value); + return output; + }).join(''); + } + + /** + * Converts a basic code point into a digit/integer. + * @see `digitToBasic()` + * @private + * @param {Number} codePoint The basic numeric code point value. + * @returns {Number} The numeric value of a basic code point (for use in + * representing integers) in the range `0` to `base - 1`, or `base` if + * the code point does not represent a value. + */ + function basicToDigit(codePoint) { + if (codePoint - 48 < 10) { + return codePoint - 22; + } + if (codePoint - 65 < 26) { + return codePoint - 65; + } + if (codePoint - 97 < 26) { + return codePoint - 97; + } + return base; + } + + /** + * Converts a digit/integer into a basic code point. + * @see `basicToDigit()` + * @private + * @param {Number} digit The numeric value of a basic code point. + * @returns {Number} The basic code point whose value (when used for + * representing integers) is `digit`, which needs to be in the range + * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is + * used; else, the lowercase form is used. The behavior is undefined + * if `flag` is non-zero and `digit` has no uppercase form. + */ + function digitToBasic(digit, flag) { + // 0..25 map to ASCII a..z or A..Z + // 26..35 map to ASCII 0..9 + return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); + } + + /** + * Bias adaptation function as per section 3.4 of RFC 3492. + * http://tools.ietf.org/html/rfc3492#section-3.4 + * @private + */ + function adapt(delta, numPoints, firstTime) { + var k = 0; + delta = firstTime ? floor(delta / damp) : delta >> 1; + delta += floor(delta / numPoints); + for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { + delta = floor(delta / baseMinusTMin); + } + return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); + } + + /** + * Converts a Punycode string of ASCII-only symbols to a string of Unicode + * symbols. + * @memberOf punycode + * @param {String} input The Punycode string of ASCII-only symbols. + * @returns {String} The resulting string of Unicode symbols. + */ + function decode(input) { + // Don't use UCS-2 + var output = [], + inputLength = input.length, + out, + i = 0, + n = initialN, + bias = initialBias, + basic, + j, + index, + oldi, + w, + k, + digit, + t, + /** Cached calculation results */ + baseMinusT; + + // Handle the basic code points: let `basic` be the number of input code + // points before the last delimiter, or `0` if there is none, then copy + // the first basic code points to the output. + + basic = input.lastIndexOf(delimiter); + if (basic < 0) { + basic = 0; + } + + for (j = 0; j < basic; ++j) { + // if it's not a basic code point + if (input.charCodeAt(j) >= 0x80) { + error('not-basic'); + } + output.push(input.charCodeAt(j)); + } + + // Main decoding loop: start just after the last delimiter if any basic code + // points were copied; start at the beginning otherwise. + + for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { + + // `index` is the index of the next character to be consumed. + // Decode a generalized variable-length integer into `delta`, + // which gets added to `i`. The overflow checking is easier + // if we increase `i` as we go, then subtract off its starting + // value at the end to obtain `delta`. + for (oldi = i, w = 1, k = base; /* no condition */; k += base) { + + if (index >= inputLength) { + error('invalid-input'); + } + + digit = basicToDigit(input.charCodeAt(index++)); + + if (digit >= base || digit > floor((maxInt - i) / w)) { + error('overflow'); + } + + i += digit * w; + t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); + + if (digit < t) { + break; + } + + baseMinusT = base - t; + if (w > floor(maxInt / baseMinusT)) { + error('overflow'); + } + + w *= baseMinusT; + + } + + out = output.length + 1; + bias = adapt(i - oldi, out, oldi == 0); + + // `i` was supposed to wrap around from `out` to `0`, + // incrementing `n` each time, so we'll fix that now: + if (floor(i / out) > maxInt - n) { + error('overflow'); + } + + n += floor(i / out); + i %= out; + + // Insert `n` at position `i` of the output + output.splice(i++, 0, n); + + } + + return ucs2encode(output); + } + + /** + * Converts a string of Unicode symbols (e.g. a domain name label) to a + * Punycode string of ASCII-only symbols. + * @memberOf punycode + * @param {String} input The string of Unicode symbols. + * @returns {String} The resulting Punycode string of ASCII-only symbols. + */ + function encode(input) { + var n, + delta, + handledCPCount, + basicLength, + bias, + j, + m, + q, + k, + t, + currentValue, + output = [], + /** `inputLength` will hold the number of code points in `input`. */ + inputLength, + /** Cached calculation results */ + handledCPCountPlusOne, + baseMinusT, + qMinusT; + + // Convert the input in UCS-2 to Unicode + input = ucs2decode(input); + + // Cache the length + inputLength = input.length; + + // Initialize the state + n = initialN; + delta = 0; + bias = initialBias; + + // Handle the basic code points + for (j = 0; j < inputLength; ++j) { + currentValue = input[j]; + if (currentValue < 0x80) { + output.push(stringFromCharCode(currentValue)); + } + } + + handledCPCount = basicLength = output.length; + + // `handledCPCount` is the number of code points that have been handled; + // `basicLength` is the number of basic code points. + + // Finish the basic string - if it is not empty - with a delimiter + if (basicLength) { + output.push(delimiter); + } + + // Main encoding loop: + while (handledCPCount < inputLength) { + + // All non-basic code points < n have been handled already. Find the next + // larger one: + for (m = maxInt, j = 0; j < inputLength; ++j) { + currentValue = input[j]; + if (currentValue >= n && currentValue < m) { + m = currentValue; + } + } + + // Increase `delta` enough to advance the decoder's state to , + // but guard against overflow + handledCPCountPlusOne = handledCPCount + 1; + if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { + error('overflow'); + } + + delta += (m - n) * handledCPCountPlusOne; + n = m; + + for (j = 0; j < inputLength; ++j) { + currentValue = input[j]; + + if (currentValue < n && ++delta > maxInt) { + error('overflow'); + } + + if (currentValue == n) { + // Represent delta as a generalized variable-length integer + for (q = delta, k = base; /* no condition */; k += base) { + t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); + if (q < t) { + break; + } + qMinusT = q - t; + baseMinusT = base - t; + output.push( + stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) + ); + q = floor(qMinusT / baseMinusT); + } + + output.push(stringFromCharCode(digitToBasic(q, 0))); + bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); + delta = 0; + ++handledCPCount; + } + } + + ++delta; + ++n; + + } + return output.join(''); + } + + /** + * Converts a Punycode string representing a domain name or an email address + * to Unicode. Only the Punycoded parts of the input will be converted, i.e. + * it doesn't matter if you call it on a string that has already been + * converted to Unicode. + * @memberOf punycode + * @param {String} input The Punycoded domain name or email address to + * convert to Unicode. + * @returns {String} The Unicode representation of the given Punycode + * string. + */ + function toUnicode(input) { + return mapDomain(input, function(string) { + return regexPunycode.test(string) + ? decode(string.slice(4).toLowerCase()) + : string; + }); + } + + /** + * Converts a Unicode string representing a domain name or an email address to + * Punycode. Only the non-ASCII parts of the domain name will be converted, + * i.e. it doesn't matter if you call it with a domain that's already in + * ASCII. + * @memberOf punycode + * @param {String} input The domain name or email address to convert, as a + * Unicode string. + * @returns {String} The Punycode representation of the given domain name or + * email address. + */ + function toASCII(input) { + return mapDomain(input, function(string) { + return regexNonASCII.test(string) + ? 'xn--' + encode(string) + : string; + }); + } + + /*--------------------------------------------------------------------------*/ + + /** Define the public API */ + punycode = { + /** + * A string representing the current Punycode.js version number. + * @memberOf punycode + * @type String + */ + 'version': '1.3.1', + /** + * An object of methods to convert from JavaScript's internal character + * representation (UCS-2) to Unicode code points, and back. + * @see + * @memberOf punycode + * @type Object + */ + 'ucs2': { + 'decode': ucs2decode, + 'encode': ucs2encode + }, + 'decode': decode, + 'encode': encode, + 'toASCII': toASCII, + 'toUnicode': toUnicode + }; + + /** Expose `punycode` */ + // Some AMD build optimizers, like r.js, check for specific condition patterns + // like the following: + if ( + typeof define == 'function' && + typeof define.amd == 'object' && + define.amd + ) { + define('punycode', function() { + return punycode; + }); + } else if (freeExports && freeModule) { + if (module.exports == freeExports) { // in Node.js or RingoJS v0.8.0+ + freeModule.exports = punycode; + } else { // in Narwhal or RingoJS v0.7.0- + for (key in punycode) { + punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); + } + } + } else { // in Rhino or a web browser + root.punycode = punycode; + } + +}(this)); + +var html2canvasNodeAttribute = "data-html2canvas-node"; +var html2canvasCanvasCloneAttribute = "data-html2canvas-canvas-clone"; +var html2canvasCanvasCloneIndex = 0; +var html2canvasCloneIndex = 0; + +window.html2canvas = function(nodeList, options) { + var index = html2canvasCloneIndex++; + options = options || {}; + if (options.logging) { + window.html2canvas.logging = true; + window.html2canvas.start = Date.now(); + } + + options.async = typeof(options.async) === "undefined" ? true : options.async; + options.allowTaint = typeof(options.allowTaint) === "undefined" ? false : options.allowTaint; + options.removeContainer = typeof(options.removeContainer) === "undefined" ? true : options.removeContainer; + options.javascriptEnabled = typeof(options.javascriptEnabled) === "undefined" ? false : options.javascriptEnabled; + options.imageTimeout = typeof(options.imageTimeout) === "undefined" ? 10000 : options.imageTimeout; + options.renderer = typeof(options.renderer) === "function" ? options.renderer : CanvasRenderer; + options.strict = !!options.strict; + + if (typeof(nodeList) === "string") { + if (typeof(options.proxy) !== "string") { + return Promise.reject("Proxy must be used when rendering url"); + } + var width = options.width != null ? options.width : window.innerWidth; + var height = options.height != null ? options.height : window.innerHeight; + return loadUrlDocument(absoluteUrl(nodeList), options.proxy, document, width, height, options).then(function(container) { + return renderWindow(container.contentWindow.document.documentElement, container, options, width, height); + }); + } + + var node = ((nodeList === undefined) ? [document.documentElement] : ((nodeList.length) ? nodeList : [nodeList]))[0]; + node.setAttribute(html2canvasNodeAttribute + index, index); + return renderDocument(node.ownerDocument, options, node.ownerDocument.defaultView.innerWidth, node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) { + if (typeof(options.onrendered) === "function") { + log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas"); + options.onrendered(canvas); + } + return canvas; + }); +}; + +window.html2canvas.punycode = this.punycode; +window.html2canvas.proxy = {}; + +function renderDocument(document, options, windowWidth, windowHeight, html2canvasIndex) { + return createWindowClone(document, document, windowWidth, windowHeight, options, document.defaultView.pageXOffset, document.defaultView.pageYOffset).then(function(container) { + log("Document cloned"); + var attributeName = html2canvasNodeAttribute + html2canvasIndex; + var selector = "[" + attributeName + "='" + html2canvasIndex + "']"; + document.querySelector(selector).removeAttribute(attributeName); + var clonedWindow = container.contentWindow; + var node = clonedWindow.document.querySelector(selector); + var oncloneHandler = (typeof(options.onclone) === "function") ? Promise.resolve(options.onclone(clonedWindow.document)) : Promise.resolve(true); + return oncloneHandler.then(function() { + return renderWindow(node, container, options, windowWidth, windowHeight); + }); + }); +} + +function renderWindow(node, container, options, windowWidth, windowHeight) { + var clonedWindow = container.contentWindow; + var support = new Support(clonedWindow.document); + var imageLoader = new ImageLoader(options, support); + var bounds = getBounds(node); + var width = options.type === "view" ? windowWidth : documentWidth(clonedWindow.document); + var height = options.type === "view" ? windowHeight : documentHeight(clonedWindow.document); + var renderer = new options.renderer(width, height, imageLoader, options, document); + var parser = new NodeParser(node, renderer, support, imageLoader, options); + return parser.ready.then(function() { + log("Finished rendering"); + var canvas; + + if (options.type === "view") { + canvas = crop(renderer.canvas, {width: renderer.canvas.width, height: renderer.canvas.height, top: 0, left: 0, x: 0, y: 0}); + } else if (node === clonedWindow.document.body || node === clonedWindow.document.documentElement || options.canvas != null) { + canvas = renderer.canvas; + } else { + canvas = crop(renderer.canvas, {width: options.width != null ? options.width : bounds.width, height: options.height != null ? options.height : bounds.height, top: bounds.top, left: bounds.left, x: clonedWindow.pageXOffset, y: clonedWindow.pageYOffset}); + } + + cleanupContainer(container, options); + return canvas; + }); +} + +function cleanupContainer(container, options) { + if (options.removeContainer) { + container.parentNode.removeChild(container); + log("Cleaned up container"); + } +} + +function crop(canvas, bounds) { + var croppedCanvas = document.createElement("canvas"); + var x1 = Math.min(canvas.width - 1, Math.max(0, bounds.left)); + var x2 = Math.min(canvas.width, Math.max(1, bounds.left + bounds.width)); + var y1 = Math.min(canvas.height - 1, Math.max(0, bounds.top)); + var y2 = Math.min(canvas.height, Math.max(1, bounds.top + bounds.height)); + croppedCanvas.width = bounds.width; + croppedCanvas.height = bounds.height; + log("Cropping canvas at:", "left:", bounds.left, "top:", bounds.top, "width:", (x2-x1), "height:", (y2-y1)); + log("Resulting crop with width", bounds.width, "and height", bounds.height, " with x", x1, "and y", y1); + croppedCanvas.getContext("2d").drawImage(canvas, x1, y1, x2-x1, y2-y1, bounds.x, bounds.y, x2-x1, y2-y1); + return croppedCanvas; +} + +function documentWidth (doc) { + return Math.max( + Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth), + Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth), + Math.max(doc.body.clientWidth, doc.documentElement.clientWidth) + ); +} + +function documentHeight (doc) { + return Math.max( + Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight), + Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight), + Math.max(doc.body.clientHeight, doc.documentElement.clientHeight) + ); +} + +function smallImage() { + return "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; +} + +function isIE9() { + return document.documentMode && document.documentMode <= 9; +} + +// https://github.com/niklasvh/html2canvas/issues/503 +function cloneNodeIE9(node, javascriptEnabled) { + var clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false); + + var child = node.firstChild; + while(child) { + if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') { + clone.appendChild(cloneNodeIE9(child, javascriptEnabled)); + } + child = child.nextSibling; + } + + return clone; +} + +function createWindowClone(ownerDocument, containerDocument, width, height, options, x ,y) { + labelCanvasElements(ownerDocument); + var documentElement = isIE9() ? cloneNodeIE9(ownerDocument.documentElement, options.javascriptEnabled) : ownerDocument.documentElement.cloneNode(true); + var container = containerDocument.createElement("iframe"); + + container.className = "html2canvas-container"; + container.style.visibility = "hidden"; + container.style.position = "fixed"; + container.style.left = "-10000px"; + container.style.top = "0px"; + container.style.border = "0"; + container.width = width; + container.height = height; + container.scrolling = "no"; // ios won't scroll without it + containerDocument.body.appendChild(container); + + return new Promise(function(resolve) { + var documentClone = container.contentWindow.document; + + cloneNodeValues(ownerDocument.documentElement, documentElement, "textarea"); + cloneNodeValues(ownerDocument.documentElement, documentElement, "select"); + + /* Chrome doesn't detect relative background-images assigned in inline /editor.css"> /lib/droplet.css"> -/lib/jquery-ui.css"> + /lib/jquery-ui-slider-pips.css"> /lib/font-awesome.css"> /lib/tooltipster/css/tooltipster.css"> diff --git a/content/lib/jquery-ui-slider-pips.js b/content/lib/jquery-ui-slider-pips.js index a1246df0..a75e202c 100644 --- a/content/lib/jquery-ui-slider-pips.js +++ b/content/lib/jquery-ui-slider-pips.js @@ -1,7 +1,3 @@ -/*! jQuery-ui-Slider-Pips - v1.10.4 - 2015-06-08 -* Copyright (c) 2015 Simon Goellner ; Licensed MIT */ - -// PIPS (function($) { @@ -12,8 +8,7 @@ pips: function( settings ) { var slider = this, i, j, p, collection = "", - mousedownHandlers = $._data( slider.element.get(0), "events").mousedown, - originalMousedown, + mousedownHandlers, min = slider._valueMin(), max = slider._valueMax(), value = slider._value(), @@ -53,12 +48,22 @@ }; - $.extend( options, settings ); + if ( $.type( settings ) === "object" || $.type( settings ) === "undefined" ) { + $.extend( options, settings ); + } else { + if ( settings === "destroy" ) { + destroy(); + } + return; + } + - slider.options.pipStep = options.step; + // we don't want the step ever to be a floating point. + slider.options.pipStep = Math.round( options.step ); // get rid of all pips that might already exist. slider.element + .off( ".selectPip" ) .addClass("ui-slider-pips") .find(".ui-slider-pip") .remove(); @@ -75,6 +80,23 @@ .filter(".ui-slider-pip-" + this.classLabel(value) ) .addClass("ui-slider-pip-selected"); + if ( slider.options.range ) { + + $pips.each(function(k,v) { + + var pipVal = $(v).children(".ui-slider-label").data("value"); + + if (( slider.options.range === "min" && pipVal < value ) || + ( slider.options.range === "max" && pipVal > value )) { + + $(v).addClass("ui-slider-pip-inrange"); + + } + + }); + + } + }, range: function(values) { @@ -174,6 +196,17 @@ } + function destroy() { + + slider.element + .off(".selectPip") + .on("mousedown.slider", slider.element.data("mousedown-original") ) + .removeClass("ui-slider-pips") + .find(".ui-slider-pip") + .remove(); + + } + // when we click on a label, we want to make sure the // slider's handle actually goes to that label! // so we check all the handles and see which one is closest @@ -304,8 +337,10 @@ for( i = 0; i < values.length; i++ ) { if ( labelValue === values[i] ) { + classes += " ui-slider-pip-initial-" + (i+1); classes += " ui-slider-pip-selected-" + (i+1); + } } @@ -324,8 +359,21 @@ } else { if ( labelValue === value ) { + classes += " ui-slider-pip-initial"; classes += " ui-slider-pip-selected"; + + } + + if ( slider.options.range ) { + + if (( slider.options.range === "min" && labelValue < value ) || + ( slider.options.range === "max" && labelValue > value )) { + + classes += " ui-slider-pip-inrange"; + + } + } } @@ -345,9 +393,6 @@ } - // we don't want the step ever to be a floating point. - slider.options.pipStep = Math.round( slider.options.pipStep ); - // create our first pip collection += createPip("first"); @@ -369,13 +414,28 @@ + // store the mousedown handlers for later, just in case we reset + // the slider, the handler would be lost! + + if ( $._data( slider.element.get(0), "events").mousedown && + $._data( slider.element.get(0), "events").mousedown.length ) { + + mousedownHandlers = $._data( slider.element.get(0), "events").mousedown; + + } else { + + mousedownHandlers = slider.element.data("mousedown-handlers"); + + } + + slider.element.data("mousedown-handlers", mousedownHandlers.slice() ); // loop through all the mousedown handlers on the slider, // and store the original namespaced (.slider) event handler so // we can trigger it later. for( j = 0; j < mousedownHandlers.length; j++ ) { if( mousedownHandlers[j].namespace === "slider" ) { - originalMousedown = mousedownHandlers[j].handler; + slider.element.data("mousedown-original", mousedownHandlers[j].handler ); } } @@ -408,6 +468,7 @@ } else { + var originalMousedown = slider.element.data("mousedown-original"); originalMousedown(e); } @@ -495,7 +556,17 @@ }; - $.extend( options, settings ); + if ( $.type( settings ) === "object" || $.type( settings ) === "undefined" ) { + $.extend( options, settings ); + } else { + if ( settings === "destroy" ) { + destroy(); + } + return; + } + + + if ( value < min ) { value = min; @@ -527,6 +598,19 @@ .find(".ui-slider-tip, .ui-slider-tip-label") .remove(); + + + function destroy() { + + slider.element + .off(".sliderFloat") + .removeClass("ui-slider-float") + .find(".ui-slider-tip, .ui-slider-tip-label") + .remove(); + + } + + function getPipLabels( values ) { // when checking the array we need to divide @@ -644,16 +728,18 @@ } // when slider changes, update handle tip label. - slider.element.on( options.event , function( e, ui ) { + slider.element + .off(".sliderFloat") + .on( options.event + ".sliderFloat", function( e, ui ) { - var uiValue = ( $.type( ui.value ) === "array" ) ? ui.value : [ ui.value ], - val = options.formatLabel( getPipLabels( uiValue )[0] ); + var uiValue = ( $.type( ui.value ) === "array" ) ? ui.value : [ ui.value ], + val = options.formatLabel( getPipLabels( uiValue )[0] ); - $(ui.handle) - .find(".ui-slider-tip") - .html( val ); + $(ui.handle) + .find(".ui-slider-tip") + .html( val ); - }); + }); } @@ -661,4 +747,4 @@ $.extend(true, $.ui.slider.prototype, extensionMethods); -})(jQuery); \ No newline at end of file +})(jQuery); From 7d676fa9fd12c380c9daa06828b406b3c4993c8d Mon Sep 17 00:00:00 2001 From: Amanda Date: Wed, 22 Jul 2015 14:47:19 -0400 Subject: [PATCH 085/199] Fixed line numbers --- content/src/view.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/content/src/view.js b/content/src/view.js index 88106bc4..16c6e9fa 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -254,12 +254,14 @@ function createSlider(traceevents, loop, screenshots, all_arrows, pane, debugRec if (traceevents[traceevents.length - 1].type == "enter" || traceevents[traceevents.length-1].type == "leave") { traceevents.pop(); + } + if (!sliderCreated) { + linenoList = [] } linenoList.push(traceevents[traceevents.length-1].location.first_line) // If slider hasn't been created and there are events being pushed, create slider. if (!sliderCreated && traceevents.length > 0){ - // Append the newly created div for the slider to the panel at bottom $(".scrubbermark").append(div); From b2d3a706e6d59cd0945ba5fcf09a1adc6b79543a Mon Sep 17 00:00:00 2001 From: Amanda Date: Wed, 22 Jul 2015 16:58:45 -0400 Subject: [PATCH 086/199] Fixing panel resizing --- content/src/editor.less | 10 +++++++--- content/src/view.js | 11 +++-------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/content/src/editor.less b/content/src/editor.less index cd29833a..6ec03705 100644 --- a/content/src/editor.less +++ b/content/src/editor.less @@ -1049,7 +1049,11 @@ body#pencildoc #diigolet-csm { cursor: row-resize; background-color: rgba(255,255,255,0); } - +/* +.hpanel.scrubbermark { + max-height: 500px; +} +*/ .hpanel:nth-of-type(1) { border-top: none } @@ -1120,8 +1124,8 @@ body#pencildoc #diigolet-csm { .scrubber { position: relative; - left: 100px; - width: 300px; + left: 10%; + width: 80%; } .scrubber.ui-slider { diff --git a/content/src/view.js b/content/src/view.js index 16c6e9fa..cd58da35 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -231,6 +231,7 @@ var playButton = false; function removeSlider () { $(".scrubber").remove(); + $(".scrubbermark").css("visibility", "hidden") sliderCreated = false; } @@ -241,6 +242,7 @@ function removePlay () { } var linenoList = []; function createSlider(traceevents, loop, screenshots, all_arrows, pane, debugRecordsByLineNo, target){ + $(".scrubbermark").css("visibility", "visible"); // var previous_line = 0; var current_line = 0; @@ -274,13 +276,6 @@ if (traceevents[traceevents.length - 1].type == "enter" || traceevents[traceeven range: "min", smooth: false, slide: function(event, ui){ - // Get the handle and add the corresponding line number above it - // $(".scrubber").find(".ui-slider-handle").text(traceevents[ui.value].location.first_line); - - /* Note: Screenshot code needs to be revamped - var canvas = $(".preview iframe")[0].contentWindow.canvas() - var drawCtx = canvas.getContext('2d'); - drawCtx.putImageData(screenshots[ui.value], 0, 0); */ // get the line of the previously selected tick and clear it var prevno = traceevents[current_line].location.first_line; @@ -2413,7 +2408,7 @@ function setPaneEditorData(pane, doc, filename, useblocks) { '
', '
', '
', - '
', + '', '
', '
', From 4c2129619a4deb54b0cada1bd824abb69c458b84 Mon Sep 17 00:00:00 2001 From: Amanda Date: Thu, 23 Jul 2015 09:08:22 -0400 Subject: [PATCH 087/199] Finalizing css --- content/src/editor.less | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/content/src/editor.less b/content/src/editor.less index 6ec03705..01bdbe4d 100644 --- a/content/src/editor.less +++ b/content/src/editor.less @@ -718,6 +718,9 @@ body#pencildoc #diigolet-csm { cursor: pointer } +.ui-slider-label { + color: black +} .blockmenu { position: absolute; top: -28px; @@ -1124,6 +1127,7 @@ body#pencildoc #diigolet-csm { .scrubber { position: relative; + top: 20%; left: 10%; width: 80%; } @@ -1144,11 +1148,12 @@ body#pencildoc #diigolet-csm { width: 16px; transform: rotateZ(360deg); } -/* .scrubber.ui-slider .ui-slider-handle.ui-state-hover, + .scrubber.ui-slider .ui-slider-handle.ui-state-hover, .scrubber.ui-slider .ui-slider-handle.ui-state-focus, .scrubber.ui-slider .ui-slider-handle.ui-state-active { - border-color: #172f38; } */ - + border-color: #172f38; } + + .scrubber.ui-slider .ui-slider-pip .ui-slider-line { background: #d5cebc; transition: all 0.4s ease; } From 12e0edbb163c20c4af6479bc7c94b9e4fc27b59e Mon Sep 17 00:00:00 2001 From: Amanda Date: Thu, 23 Jul 2015 09:08:48 -0400 Subject: [PATCH 088/199] Finalizing css --- content/lib/jquery-ui-slider-pips.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/lib/jquery-ui-slider-pips.css b/content/lib/jquery-ui-slider-pips.css index 615a87f5..e2268386 100644 --- a/content/lib/jquery-ui-slider-pips.css +++ b/content/lib/jquery-ui-slider-pips.css @@ -68,10 +68,10 @@ } /* make it easy to see when we hover a label */ - .ui-slider-pips:not(.ui-slider-disabled) .ui-slider-pip:hover .ui-slider-label { + /* .ui-slider-pips:not(.ui-slider-disabled) .ui-slider-pip:hover .ui-slider-label { color: black; font-weight: bold; - } + } */ From d63b42825e51054926af9236ffb6c7a11c67cc60 Mon Sep 17 00:00:00 2001 From: Amanda Date: Thu, 23 Jul 2015 09:31:34 -0400 Subject: [PATCH 089/199] Removed extra logging --- content/src/view.js | 1 - 1 file changed, 1 deletion(-) diff --git a/content/src/view.js b/content/src/view.js index cd58da35..80a1b1e9 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -90,7 +90,6 @@ ZeroClipboard.config({ window.pencilcode.view = { // Listens to events on: function(tag, cb) { - console.log("this is being called"); if (state.callbacks[tag] == null){ state.callbacks[tag] = [] } From 1c815788f82cfde019aea3cf4a6b00fd02571e67 Mon Sep 17 00:00:00 2001 From: Amanda Date: Fri, 24 Jul 2015 11:07:37 -0400 Subject: [PATCH 090/199] Created buttons --- content/src/debug.js | 7 +-- content/src/editor.less | 20 +++++---- content/src/view.js | 96 ++++++++++++++++++++++++++++++----------- 3 files changed, 86 insertions(+), 37 deletions(-) diff --git a/content/src/debug.js b/content/src/debug.js index 8f663ac9..bb735d6e 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -838,10 +838,11 @@ view.on('delta', function(){ /////////////////////////////////////////////////////////////////////////// // STEP BUTTON SUPPORT /////////////////////////////////////////////////////////////////////////// -view.on('.p_button', function(){ - console.log("remove"); +$("#backButton").click(function() { + console.log("ok"); -}); + +}) /////////////////////////////////////////////////////////////////////////// // DEBUG EXPORT diff --git a/content/src/editor.less b/content/src/editor.less index 01bdbe4d..243b8ead 100644 --- a/content/src/editor.less +++ b/content/src/editor.less @@ -563,17 +563,19 @@ body.modal #middle { margin: -1px -4px -1px 4px; } -.p_button { - width: 0; - height: 0; - font-size: 0; - line-height: 0; - border-bottom: 19px solid transparent; - border-top: 19px solid transparent; - border-left: 36px solid #1e90ff; - margin: -1px -4px -1px 4px; +#backButton { + position: relative; + float: left; + display: block; + top: 200px; } +#forwardButton { + position: relative; + float: left; + display: block; + top: 200 px; +} #run .reload { width: 36px; diff --git a/content/src/view.js b/content/src/view.js index 80a1b1e9..22b476d2 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -230,6 +230,8 @@ var playButton = false; function removeSlider () { $(".scrubber").remove(); + $("#backButton").remove(); + $("#forwardButton").remove(); $(".scrubbermark").css("visibility", "hidden") sliderCreated = false; @@ -238,16 +240,49 @@ function removeSlider () { function removePlay () { $(".p_button").remove(); playButton = false; -} +} + var linenoList = []; +var current_line = 0; +var previous_line = 0; + +function change(event, ui, traceevents, debugRecordsByLineNo, target, pane, all_arrows ) { + var prevno = traceevents[previous_line].location.first_line; + clearPaneEditorLine(paneid('left'), prevno, 'debugtrace'); + + // after clearing, set the current line to the selected ui value + current_line = ui.value + previous_line = current_line + // get the new line number of the selected value + var lineno = traceevents[current_line].location.first_line; + + // Drawing arrows at each step in the slider + arrow(pane, all_arrows, current_line); + + // display the protractor for that new line and highlight the selected line + hideProtractor(paneid('right')); + displayProtractorForRecord(debugRecordsByLineNo[lineno], target); + markPaneEditorLine( + paneid('left'), lineno, 'guttermouseable', true); + markPaneEditorLine(paneid('left'), lineno, 'debugtrace'); + } + + + + + + + function createSlider(traceevents, loop, screenshots, all_arrows, pane, debugRecordsByLineNo, target){ $(".scrubbermark").css("visibility", "visible"); // var previous_line = 0; - var current_line = 0; + // Create div element for scrubbber var div = document.createElement('div'); div.className = 'scrubber'; + + var firstLabel = (1).toString(); var secondLabel = (traceevents.length).toString(); @@ -263,9 +298,21 @@ if (traceevents[traceevents.length - 1].type == "enter" || traceevents[traceeven // If slider hasn't been created and there are events being pushed, create slider. if (!sliderCreated && traceevents.length > 0){ + current_line = 0; + previous_line = 0; + var backDiv = document.createElement('div'); + var forwardDiv = document.createElement('div'); + // Append the newly created div for the slider to the panel at bottom - $(".scrubbermark").append(div); + $(".scrubbermark").append(div); + + backDiv.innerHTML = ""; + $(".scrubbermark").append(backDiv); + + forwardDiv = document.createElement('div'); + forwardDiv.innerHTML = ""; + $(".scrubbermark").append(forwardDiv); // Code for the slider $(function() { $(".scrubber").slider({ @@ -273,30 +320,16 @@ if (traceevents[traceevents.length - 1].type == "enter" || traceevents[traceeven max: traceevents.length - 1, step: 1, range: "min", + value: current_line, smooth: false, - slide: function(event, ui){ - - // get the line of the previously selected tick and clear it - var prevno = traceevents[current_line].location.first_line; - clearPaneEditorLine(paneid('left'), prevno, 'debugtrace'); + change: function(event, ui) { + change(event, ui, traceevents, debugRecordsByLineNo, target, pane, all_arrows) + }, + slide: function(event, ui) { - // after clearing, set the current line to the selected ui value - current_line = ui.value - - // get the new line number of the selected value - var lineno = traceevents[current_line].location.first_line; - - // Drawing arrows at each step in the slider - arrow(pane, all_arrows, current_line); + change(event, ui, traceevents, debugRecordsByLineNo, target, pane, all_arrows); - - // display the protractor for that new line and highlight the selected line - hideProtractor(paneid('right')); - displayProtractorForRecord(debugRecordsByLineNo[lineno], target); - markPaneEditorLine( - paneid('left'), lineno, 'guttermouseable', true); - markPaneEditorLine(paneid('left'), lineno, 'debugtrace'); - } + } }) .slider("pips", { first: "label", @@ -308,11 +341,24 @@ if (traceevents[traceevents.length - 1].type == "enter" || traceevents[traceeven labels: linenoList, prefix: "Line " }) - +$('#backButton').on('click', function() { + if (current_line != 0) { + current_line--; + $(".scrubber").slider("value",current_line); +} +}); + +$('#forwardButton').on('click', function() { + if (current_line != traceevents.length - 1) { + current_line++ + $(".scrubber").slider("value", current_line); +} +}) // keep as variable so number of pips and maximum can be modified as events are pushed var max = $( ".scrubber" ).slider("option", "max"); var pips = $(".scrubber").slider("option", "pips"); }); + // the slider has been created sliderCreated = true; } From 77b00c8f18d375e1dc6ad1ead6a1199a4950de7e Mon Sep 17 00:00:00 2001 From: Amanda Date: Fri, 24 Jul 2015 11:43:49 -0400 Subject: [PATCH 091/199] Made some minor improvements --- content/src/editor.less | 14 -------------- content/src/view.js | 3 ++- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/content/src/editor.less b/content/src/editor.less index 243b8ead..490ca9a4 100644 --- a/content/src/editor.less +++ b/content/src/editor.less @@ -563,20 +563,6 @@ body.modal #middle { margin: -1px -4px -1px 4px; } -#backButton { - position: relative; - float: left; - display: block; - top: 200px; -} - -#forwardButton { - position: relative; - float: left; - display: block; - top: 200 px; -} - #run .reload { width: 36px; height: 36px; diff --git a/content/src/view.js b/content/src/view.js index b8eb9c87..688b92c1 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -247,6 +247,7 @@ var current_line = 0; var previous_line = 0; function change(event, ui, traceevents, debugRecordsByLineNo, target, pane, all_arrows ) { + console.log(traceevents); var prevno = traceevents[previous_line].location.first_line; clearPaneEditorLine(paneid('left'), prevno, 'debugtrace'); @@ -388,7 +389,7 @@ $('#forwardButton').on('click', function() { } $(".scrubber").slider("option", "max", traceevents.length - 1) $(".scrubber").slider("option", "step", Math.round( traceevents.length/100)); - $(".scrubber").slider("pips",{ rest: "pip" }).slider("float", { labels: linenoList }) + $(".scrubber").slider("pips",{ first: "label", rest: "pip", last: "label", labels: {"first": firstLabel.concat(" Step"),"last": secondLabel.concat(" Steps") } }).slider("float", { labels: linenoList, prefix: "Line " }) } From 18127a000e1b5e65e4423e9b0b049a31b92edaac Mon Sep 17 00:00:00 2001 From: Amanda Date: Fri, 24 Jul 2015 13:32:01 -0400 Subject: [PATCH 092/199] Merged --- content/src/debug.js | 2 +- content/src/view.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/content/src/debug.js b/content/src/debug.js index bb735d6e..4acc200f 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -138,7 +138,7 @@ var debug = window.ide = { panel: embedded ? 'auto' : true }; }, - trace: function(event, data) { + trace: function(event, data) { detectStuckProgram(); // This receives events for the new debugger to use. currentDebugId += 1; diff --git a/content/src/view.js b/content/src/view.js index 688b92c1..6b7cd50f 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -247,7 +247,6 @@ var current_line = 0; var previous_line = 0; function change(event, ui, traceevents, debugRecordsByLineNo, target, pane, all_arrows ) { - console.log(traceevents); var prevno = traceevents[previous_line].location.first_line; clearPaneEditorLine(paneid('left'), prevno, 'debugtrace'); From 698ad8e5c0ea1a69e7102ac4f005a8570b6de7d7 Mon Sep 17 00:00:00 2001 From: Amanda Date: Fri, 24 Jul 2015 19:05:23 -0400 Subject: [PATCH 093/199] cleaned up files --- content/src/debug.js | 48 ++------ content/src/editor.less | 68 ++++++------ content/src/protractor.js | 60 ++++++++++ content/src/view.js | 223 +++++++++++++++++--------------------- 4 files changed, 206 insertions(+), 193 deletions(-) create mode 100644 content/src/protractor.js diff --git a/content/src/debug.js b/content/src/debug.js index 4acc200f..e88263cb 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -21,11 +21,8 @@ var pollTimer = null; // poll for stop button. var stopButtonShown = 0; // 0 = not shown; 1 = shown; 2 = stopped. var currentSourceMap = null; // v3 source map for currently-running instrumented code. var traceEvents = []; // list of event location objects created by tracing events -var screenshots = []; -var turtle_screenshots = []; -var stuckTime = null; // timestmp to detect stuck programs -var arrows = {}; -var temp_screenshots = []; +var stuckTime = null; // timestmp to detect stuck programs +var arrows = {}; // keep track of arrows that appear in the program // verification of complexity of stuck loop var stuckComplexity = { @@ -56,12 +53,9 @@ function bindframe(w) { arrows = {}; currentEventIndex = 0; prevEventIndex = -1; - isLoop = false; -// linesRun = 0; view.clearPaneEditorMarks(view.paneid('left')); view.notePaneEditorCleanLineCount(view.paneid('left')); view.removeSlider(); - view.removePlay(); stuckTime = null; stuckComplexity = { lines: 0, @@ -147,7 +141,7 @@ var debug = window.ide = { currentEventIndex = traceEvents.length - 1; record.eventIndex = currentEventIndex; var lineno = traceEvents[currentEventIndex].location.first_line; - view.createSlider(traceEvents, isLoop, screenshots, arrows, view.paneid("left"), debugRecordsByLineNo, targetWindow); + view.createSlider(traceEvents, arrows, view.paneid("left"), debugRecordsByLineNo, targetWindow); record.line = lineno; debugRecordsByDebugId[currentDebugId] = record; debugRecordsByLineNo[lineno] = record; @@ -224,7 +218,6 @@ function reportSeeeval(method, debugId, length, coordId, elem, args){ function reportAppear(method, debugId, length, coordId, elem, args){ - var currentLine = traceEvents[currentIndex].location.first_line; var currentLocation = traceEvents[currentIndex].location; var prevLine = -1; @@ -234,14 +227,6 @@ function reportAppear(method, debugId, length, coordId, elem, args){ var recordD = debugRecordsByDebugId[debugId]; if (recordD) { if (!recordD.seeeval){ - /* html2canvas(document.getElementById('output-frame').contentDocument.getElementsByClassName('turtlefield')[1],{ - onrendered: function(canvas){ - temp_screenshots.push(canvas); - var tempCanvas = document.createElement('canvas'); - var tempCanvasCtx = tempCanvas.getContext('2d'); - tempCanvasCtx.drawImage(canvas,0,0); - } - })*/ var recordL = debugRecordsByLineNo[recordD.line]; recordD.method = method; recordL.method = method; @@ -253,31 +238,30 @@ function reportAppear(method, debugId, length, coordId, elem, args){ var tracedLine = -1; //trace lines that are not animation. - while (line != currentLine){ - + while (line != currentLine) { if (prevIndex != -1) { var prevLocation = traceEvents[prevIndex].location; var prevLine = prevLocation.first_line; } - else{ + else { var prevLocation = null; var prevLine = -1; } - if (tracedLine != -1){ + if (tracedLine != -1) { untraceLine(tracedLine); tracedLine = -1; } - if(currentLine < prevLine){ + if(currentLine < prevLine) { - if (arrows[prevIndex] != null){ + if (arrows[prevIndex] != null) { arrows[prevIndex]['after'] = {first: currentLocation, second: prevLocation}; } - else{ + else { arrows[prevIndex] = {before: null, after: {first: currentLocation, second: prevLocation}}; } - if (arrows[currentIndex] != null){ + if (arrows[currentIndex] != null) { arrows[currentIndex]['before'] = {first: currentLocation, second: prevLocation}; } else{ @@ -293,7 +277,7 @@ function reportAppear(method, debugId, length, coordId, elem, args){ currentLine = traceEvents[currentIndex].location.first_line; currentLocation = traceEvents[currentIndex].location; } - if (tracedLine != -1){ + if (tracedLine != -1) { untraceLine(tracedLine); tracedLine = -1; } @@ -834,16 +818,6 @@ view.on('delta', function(){ //need to add code that stops animation!!! }); - -/////////////////////////////////////////////////////////////////////////// -// STEP BUTTON SUPPORT -/////////////////////////////////////////////////////////////////////////// -$("#backButton").click(function() { - console.log("ok"); - - -}) - /////////////////////////////////////////////////////////////////////////// // DEBUG EXPORT /////////////////////////////////////////////////////////////////////////// diff --git a/content/src/editor.less b/content/src/editor.less index 490ca9a4..de8f52fb 100644 --- a/content/src/editor.less +++ b/content/src/editor.less @@ -1040,11 +1040,7 @@ body#pencildoc #diigolet-csm { cursor: row-resize; background-color: rgba(255,255,255,0); } -/* -.hpanel.scrubbermark { - max-height: 500px; -} -*/ + .hpanel:nth-of-type(1) { border-top: none } @@ -1058,7 +1054,9 @@ body#pencildoc #diigolet-csm { z-index: 999999 } -.arrow { pointer-events:none; } +.arrow { + pointer-events:none; +} #pencildoc .droplet-palette-header { border: 0; @@ -1123,51 +1121,55 @@ body#pencildoc #diigolet-csm { .scrubber.ui-slider { background: #d5cebc; border: none; - border-radius: 0; } + border-radius: 0; +} .scrubber .ui-slider-tip { visibility: visible; opacity: 1; top: -30px; -} +} + .scrubber.ui-slider .ui-slider-handle { top: -6px; height: 16px; width: 16px; - transform: rotateZ(360deg); } + transform: rotateZ(360deg); +} - .scrubber.ui-slider .ui-slider-handle.ui-state-hover, - .scrubber.ui-slider .ui-slider-handle.ui-state-focus, - .scrubber.ui-slider .ui-slider-handle.ui-state-active { - border-color: #172f38; } +.scrubber.ui-slider .ui-slider-handle.ui-state-hover, +.scrubber.ui-slider .ui-slider-handle.ui-state-focus, +.scrubber.ui-slider .ui-slider-handle.ui-state-active { + border-color: #172f38; +} .scrubber.ui-slider .ui-slider-pip .ui-slider-line { background: #d5cebc; - transition: all 0.4s ease; } + transition: all 0.4s ease; +} .scrubber.ui-slider.ui-slider-horizontal { - height: 6px; } - - /* .scrubber.ui-slider.ui-slider-horizontal .ui-slider-handle { - -webkit-transform: rotateZ(45deg); - transform: rotateZ(45deg); - top: -25px; - margin-left: -10px; } */ - - .scrubber.ui-slider.ui-slider-horizontal .ui-slider-pip { - top: 10px; } - - .scrubber.ui-slider.ui-slider-horizontal .ui-slider-pip .ui-slider-line { - width: 2px; - height: 10px; - margin-left: -1px; } + height: 6px; +} - .scrubber.ui-slider.ui-slider-horizontal .ui-slider-pip[class*=ui-slider-pip-selected] .ui-slider-line { - height: 20px; } +.scrubber.ui-slider.ui-slider-horizontal .ui-slider-pip { + top: 10px; +} - .scrubber.ui-slider.ui-slider-horizontal .ui-slider-pip.ui-slider-pip-inrange .ui-slider-line { - height: 12px; } +.scrubber.ui-slider.ui-slider-horizontal .ui-slider-pip .ui-slider-line { + width: 2px; + height: 10px; + margin-left: -1px; +} + +.scrubber.ui-slider.ui-slider-horizontal .ui-slider-pip[class*=ui-slider-pip-selected] .ui-slider-line { + height: 20px; +} + +.scrubber.ui-slider.ui-slider-horizontal .ui-slider-pip.ui-slider-pip-inrange .ui-slider-line { + height: 12px; +} .texttoggle, .blocktoggle { position: absolute; diff --git a/content/src/protractor.js b/content/src/protractor.js new file mode 100644 index 00000000..2debd2b2 --- /dev/null +++ b/content/src/protractor.js @@ -0,0 +1,60 @@ +/////////////////////////////////////////////////////////////////////////// +// DISPLAY PROTRACTOR SUPPORT +/////////////////////////////////////////////////////////////////////////// + +var $ = require('jquery'), + see = require('see'); + +window.pencilcode.protractor = { + displayProtractor: displayProtractor +}; + +function parseTurtleTransform(transform) { + if (transform === 'none') { + return {tx: 0, ty: 0, rot: 0, sx: 1, sy: 1, twi: 0}; + } + // Note that although the CSS spec doesn't allow 'e' in numbers, IE10 + // and FF put them in there; so allow them. + var e = /^(?:translate\(([\-+.\de]+)(?:px)?,\s*([\-+.\de]+)(?:px)?\)\s*)?(?:rotate\(([\-+.\de]+)(?:deg)?\)\s*)?(?:scale\(([\-+.\de]+)(?:,\s*([\-+.\de]+))?\)\s*)?(?:rotate\(([\-+.\de]+)(?:deg)?\)\s*)?$/.exec(transform); + if (!e) { return null; } + var tx = e[1] ? parseFloat(e[1]) : 0, + ty = e[2] ? parseFloat(e[2]) : 0, + rot = e[3] ? parseFloat(e[3]) : 0, + sx = e[4] ? parseFloat(e[4]) : 1, + sy = e[5] ? parseFloat(e[5]) : sx, + twi = e[6] ? parseFloat(e[6]) : 0; + return {tx:tx, ty:ty, rot:rot, sx:sx, sy:sy, twi:twi}; +} + +function convertCoords(origin, astransform) { + if (!origin) { return null; } + if (!astransform || !astransform.transform) { return null; } + var parsed = parseTurtleTransform(astransform.transform); + if (!parsed) return null; + return { + pageX: origin.left + parsed.tx, + pageY: origin.top + parsed.ty, + direction: parsed.rot, + scale: parsed.sy + }; +} + +function displayProtractor(record) { + // TODO: generalize this for turtles that are not in the main field. + var origin = targetWindow.jQuery('#field').offset(); + var step = { + startCoords: convertCoords( + origin, record.startCoords[record.startCoords.length - 1]), + endCoords: convertCoords( + origin, record.endCoords[record.endCoords.length - 1]), + command: record.method, + args: record.args + }; +// view.showProtractor(view.paneid('right'), step); +} + +/////////////////////////////////////////////////////////////////////////// +// DISPLAY PROTRACTOR SUPPORT +/////////////////////////////////////////////////////////////////////////// + +module.exports = protractor; \ No newline at end of file diff --git a/content/src/view.js b/content/src/view.js index 6b7cd50f..57f40f7f 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -139,9 +139,9 @@ window.pencilcode.view = { hideProtractor: hideProtractor, createSlider: createSlider, removeSlider: removeSlider, - removePlay: removePlay, setPrimaryFocus: setPrimaryFocus, - arrow:arrow, + initializeSlider: initializeSlider, + arrow: arrow, // setPaneRunUrl: setPaneRunUrl, hideEditor: function(pane) { $('#' + pane + 'title').hide(); @@ -226,145 +226,137 @@ function paneid(position) { } var sliderCreated = false; -var playButton = false; -function removeSlider () { +function removeSlider() { $(".scrubber").remove(); - $("#backButton").remove(); - $("#forwardButton").remove(); - $(".scrubbermark").css("visibility", "hidden") - sliderCreated = false; - + $("#backButton").remove(); + $("#forwardButton").remove(); + $(".scrubbermark").css("visibility", "hidden") + sliderCreated = false; } -function removePlay () { - $(".p_button").remove(); - playButton = false; -} - var linenoList = []; var current_line = 0; var previous_line = 0; function change(event, ui, traceevents, debugRecordsByLineNo, target, pane, all_arrows ) { - var prevno = traceevents[previous_line].location.first_line; - clearPaneEditorLine(paneid('left'), prevno, 'debugtrace'); - - // after clearing, set the current line to the selected ui value - current_line = ui.value - previous_line = current_line - // get the new line number of the selected value - var lineno = traceevents[current_line].location.first_line; - - // Drawing arrows at each step in the slider - arrow(pane, all_arrows, current_line); - - // display the protractor for that new line and highlight the selected line - hideProtractor(paneid('right')); - displayProtractorForRecord(debugRecordsByLineNo[lineno], target); - markPaneEditorLine( - paneid('left'), lineno, 'guttermouseable', true); - markPaneEditorLine(paneid('left'), lineno, 'debugtrace'); - } - - + // need this previous line for the forward and back buttons to work + var prevno = traceevents[previous_line].location.first_line; + clearPaneEditorLine(paneid('left'), prevno, 'debugtrace'); + // after clearing, set the current line to the selected ui value + current_line = ui.value; + previous_line = current_line; + // get the new line number of the selected value + var lineno = traceevents[current_line].location.first_line; + // Drawing arrows at each step in the slider + arrow(pane, all_arrows, current_line); + + // ISSUE: CIRCULAR DEPENDICIES + // display the protractor for that new line and highlight the selected line + hideProtractor(paneid('right')); + displayProtractorForRecord(debugRecordsByLineNo[lineno], target); + markPaneEditorLine( + paneid('left'), lineno, 'guttermouseable', true); + markPaneEditorLine(paneid('left'), lineno, 'debugtrace'); +} +function initializeSlider (traceevents, all_arrows, pane, debugRecordsByLineNo, target) { + // Create div element for scrubbber + var div = document.createElement('div'); + div.className = 'scrubber'; -function createSlider(traceevents, loop, screenshots, all_arrows, pane, debugRecordsByLineNo, target){ - $(".scrubbermark").css("visibility", "visible"); -// var previous_line = 0; + current_line = 0; + previous_line = 0; + var backDiv = document.createElement('div'); + var forwardDiv = document.createElement('div'); + + // Append the newly created div for the slider to the panel at bottom + $(".scrubbermark").append(div); + + backDiv.innerHTML = ""; + $(".scrubbermark").append(backDiv); + + forwardDiv = document.createElement('div'); + forwardDiv.innerHTML = ""; + + $(".scrubbermark").append(forwardDiv); + // Code for the slider + $(function() { + $(".scrubber").slider({ + min: 0, + max: traceevents.length - 1, + step: 1, + range: "min", + value: current_line, + smooth: false, + change: function(event, ui) { + change(event, ui, traceevents, debugRecordsByLineNo, target, pane, all_arrows) + }, + slide: function(event, ui) { + change(event, ui, traceevents, debugRecordsByLineNo, target, pane, all_arrows); + } + }) + .slider("pips", { + first: "label", + rest: "pip", + last: "label", + labels: {"first": "1 step", "last": "1 step"} + }) + .slider("float", { + labels: linenoList, + prefix: "Line " + }) + }); +} - // Create div element for scrubbber - var div = document.createElement('div'); - div.className = 'scrubber'; +function createSlider(traceevents, all_arrows, pane, debugRecordsByLineNo, target) { + $(".scrubbermark").css("visibility", "visible"); + + if (traceevents[traceevents.length - 1].type == "enter" || traceevents[traceevents.length-1].type == "leave") { + traceevents.pop(); + } - - var firstLabel = (1).toString(); var secondLabel = (traceevents.length).toString(); - -if (traceevents[traceevents.length - 1].type == "enter" || traceevents[traceevents.length-1].type == "leave") { - traceevents.pop(); - } + // reset the list of line numbers before pushing a new number if (!sliderCreated) { - linenoList = [] + linenoList = []; } + linenoList.push(traceevents[traceevents.length-1].location.first_line) // If slider hasn't been created and there are events being pushed, create slider. - if (!sliderCreated && traceevents.length > 0){ - current_line = 0; - previous_line = 0; - var backDiv = document.createElement('div'); - var forwardDiv = document.createElement('div'); - - // Append the newly created div for the slider to the panel at bottom - $(".scrubbermark").append(div); - - backDiv.innerHTML = ""; - $(".scrubbermark").append(backDiv); - - forwardDiv = document.createElement('div'); - forwardDiv.innerHTML = ""; - - $(".scrubbermark").append(forwardDiv); - // Code for the slider - $(function() { - $(".scrubber").slider({ - min: 0, - max: traceevents.length - 1, - step: 1, - range: "min", - value: current_line, - smooth: false, - change: function(event, ui) { - change(event, ui, traceevents, debugRecordsByLineNo, target, pane, all_arrows) - }, - slide: function(event, ui) { - - change(event, ui, traceevents, debugRecordsByLineNo, target, pane, all_arrows); - - } - }) - .slider("pips", { - first: "label", - rest: "pip", - last: "label", - labels: {"first": firstLabel.concat(" Step"), "last": secondLabel.concat(" Steps")} - }) - .slider("float", { - labels: linenoList, - prefix: "Line " - }) -$('#backButton').on('click', function() { - if (current_line != 0) { - current_line--; - $(".scrubber").slider("value",current_line); -} -}); - -$('#forwardButton').on('click', function() { - if (current_line != traceevents.length - 1) { - current_line++ - $(".scrubber").slider("value", current_line); -} -}) + if (!sliderCreated && traceevents.length > 0) { + initializeSlider (traceevents, all_arrows, pane, debugRecordsByLineNo, target); + $('#backButton').on('click', function() { + if (current_line != 0) { + current_line--; + $(".scrubber").slider("value",current_line); + } + }); + + $('#forwardButton').on('click', function() { + if (current_line != traceevents.length - 1) { + current_line++ + $(".scrubber").slider("value", current_line); + } + }); + // keep as variable so number of pips and maximum can be modified as events are pushed var max = $( ".scrubber" ).slider("option", "max"); var pips = $(".scrubber").slider("option", "pips"); - }); - + // the slider has been created sliderCreated = true; } // if the slider has already been created and events are pushed, modify existing slider - else if(sliderCreated && traceevents.length < 100){ + if(sliderCreated){ $(".scrubber").slider("option", "max", traceevents.length - 1) $(".scrubber").slider("pips",{ first: "label", @@ -377,21 +369,6 @@ $('#forwardButton').on('click', function() { prefix: "Line " }) } - - // remove the slider - else { - if (!playButton) { - var buttonDiv = document.createElement("div"); - buttonDiv.className = 'p_button'; - $(".scrubbermark").append(buttonDiv); - playButton = true; - } - $(".scrubber").slider("option", "max", traceevents.length - 1) - $(".scrubber").slider("option", "step", Math.round( traceevents.length/100)); - $(".scrubber").slider("pips",{ first: "label", rest: "pip", last: "label", labels: {"first": firstLabel.concat(" Step"),"last": secondLabel.concat(" Steps") } }).slider("float", { labels: linenoList, prefix: "Line " }) - - } - } function parseTurtleTransform(transform) { From 4e8b8d2478a49160742bd8bbe66f09d88f0d8ad4 Mon Sep 17 00:00:00 2001 From: Amanda Date: Mon, 27 Jul 2015 11:08:53 -0400 Subject: [PATCH 094/199] Fixed delay and processingjs compatibility --- content/src/debug.js | 2 +- content/src/view.js | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/content/src/debug.js b/content/src/debug.js index e88263cb..cfc2ee53 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -141,7 +141,7 @@ var debug = window.ide = { currentEventIndex = traceEvents.length - 1; record.eventIndex = currentEventIndex; var lineno = traceEvents[currentEventIndex].location.first_line; - view.createSlider(traceEvents, arrows, view.paneid("left"), debugRecordsByLineNo, targetWindow); + setTimeout(function() {view.createSlider(traceEvents, arrows, view.paneid("left"), debugRecordsByLineNo, targetWindow)}, 1000); record.line = lineno; debugRecordsByDebugId[currentDebugId] = record; debugRecordsByLineNo[lineno] = record; diff --git a/content/src/view.js b/content/src/view.js index 57f40f7f..2a33c6d2 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -257,7 +257,10 @@ function change(event, ui, traceevents, debugRecordsByLineNo, target, pane, all_ // ISSUE: CIRCULAR DEPENDICIES // display the protractor for that new line and highlight the selected line hideProtractor(paneid('right')); - displayProtractorForRecord(debugRecordsByLineNo[lineno], target); + if (target.jQuery != null) { + + displayProtractorForRecord(debugRecordsByLineNo[lineno], target); + } markPaneEditorLine( paneid('left'), lineno, 'guttermouseable', true); markPaneEditorLine(paneid('left'), lineno, 'debugtrace'); @@ -327,9 +330,9 @@ function createSlider(traceevents, all_arrows, pane, debugRecordsByLineNo, targe if (!sliderCreated) { linenoList = []; } - - linenoList.push(traceevents[traceevents.length-1].location.first_line) - + for (var i = 0; i < traceevents.length; i++) { + linenoList[i] = (traceevents[i].location.first_line) + } // If slider hasn't been created and there are events being pushed, create slider. if (!sliderCreated && traceevents.length > 0) { initializeSlider (traceevents, all_arrows, pane, debugRecordsByLineNo, target); From bf292bafa623900700bb50e050007de7c5802421 Mon Sep 17 00:00:00 2001 From: calistenson Date: Mon, 27 Jul 2015 13:37:29 -0400 Subject: [PATCH 095/199] updated line highlighting to work based on debugIDs and animation event indices. Still a few bugs, but works better than previous version. --- content/src/debug.js | 71 +++++++++++++++++++++++++++++++------------- content/src/view.js | 3 ++ 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/content/src/debug.js b/content/src/debug.js index e88263cb..4ea11c0e 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -11,7 +11,7 @@ var $ = require('jquery'), eval(see.scope('debug')); var targetWindow = null; // window object of the frame being debugged. -var currentIndex = 0; // current index into traceEvents. +var currentRecordID = 1; // current index into traceEvents. var prevIndex = -1; // previous index of prior traceEvent. var currentDebugId = 0; // id used to pair jquery-turtle events with trace events. var debugRecordsByDebugId = {};// map debug ids -> line execution records. @@ -51,8 +51,9 @@ function bindframe(w) { traceEvents = []; screenshots = []; arrows = {}; - currentEventIndex = 0; - prevEventIndex = -1; + currentRecordID = 1; + currentDebugId = 0; + prevIndex = -1; view.clearPaneEditorMarks(view.paneid('left')); view.notePaneEditorCleanLineCount(view.paneid('left')); view.removeSlider(); @@ -89,7 +90,7 @@ var debug = window.ide = { if (name === "seeeval") { reportSeeeval.apply(null, data); } - if (name === "enter") { stuckComplexity.calls += 1; } + if (name === "enter") { reportEnter.apply(null, data); stuckComplexity.calls += 1; } if (name === "appear") { reportAppear.apply(null, data); } @@ -136,7 +137,8 @@ var debug = window.ide = { detectStuckProgram(); // This receives events for the new debugger to use. currentDebugId += 1; - var record = {line: 0, eventIndex: null, startCoords: [], endCoords: [], method: "", data: "", seeeval:false}; + var record = {line: 0, eventIndex: null, startCoords: [], endCoords: [], method: "", + data: "", seeeval:false}; traceEvents.push(event); currentEventIndex = traceEvents.length - 1; record.eventIndex = currentEventIndex; @@ -216,10 +218,28 @@ function reportSeeeval(method, debugId, length, coordId, elem, args){ debugRecordsByDebugId[currentDebugId] = record; } +function reportEnter(method, debugId, length, coordId, elem, args){ + var recordD = debugRecordsByDebugId[debugId]; + var recordL = debugRecordsByLineNo[recordD.line]; + recordD.method = method; + recordL.method = method; + recordD.args = args; + recordL.args = args; + recordD.animated = false; + recordL.animated = false; +} + function reportAppear(method, debugId, length, coordId, elem, args){ - var currentLine = traceEvents[currentIndex].location.first_line; + console.log("currentRecordID: ", currentRecordID); + + console.log("debugRecordsByDebugId: ", debugRecordsByDebugId); + var currentRecord = debugRecordsByDebugId[currentRecordID]; + console.log("currentRecord: ", currentRecord); + var currentIndex = currentRecord.eventIndex; var currentLocation = traceEvents[currentIndex].location; + var currentLine = currentLocation.first_line; + var prevLine = -1; stuckComplexity.moves += 1; @@ -228,17 +248,13 @@ function reportAppear(method, debugId, length, coordId, elem, args){ if (recordD) { if (!recordD.seeeval){ var recordL = debugRecordsByLineNo[recordD.line]; - recordD.method = method; - recordL.method = method; - recordD.args = args; - recordL.args = args; var index = recordD.eventIndex; var line = traceEvents[index].location.first_line; var appear_location = traceEvents[index].location; var tracedLine = -1; //trace lines that are not animation. - while (line != currentLine) { + while (currentRecordID < debugId) { if (prevIndex != -1) { var prevLocation = traceEvents[prevIndex].location; var prevLine = prevLocation.first_line; @@ -267,13 +283,15 @@ function reportAppear(method, debugId, length, coordId, elem, args){ else{ arrows[currentIndex] = {before: {first: currentLocation, second: prevLocation}, after : null}; } - view.arrow(view.paneid('left'), arrows, currentIndex);//should I pass in prevIndex and currentIndex or? + view.arrow(view.paneid('left'), arrows, currentRecordID);//should I pass in prevIndex and currentRecordID or? } traceLine(currentLine); tracedLine = currentLine; prevLine = currentLine; - prevIndex = currentIndex; - currentIndex += 1; + prevIndex = debugRecordsByDebugId[currentRecordID].eventIndex; + currentRecordID += 1; + currentRecord = debugRecordsByDebugId[currentRecordID]; + currentIndex = currentRecord.eventIndex currentLine = traceEvents[currentIndex].location.first_line; currentLocation = traceEvents[currentIndex].location; } @@ -297,8 +315,9 @@ function reportAppear(method, debugId, length, coordId, elem, args){ else{ arrows[index] = {before: {first: currentLocation, second: prevLocation}, after : null}; } - view.arrow(view.paneid('left'), arrows, currentIndex);//should I pass in prevIndex and currentIndex or? + view.arrow(view.paneid('left'), arrows, currentRecordID);//should I pass in prevIndex and currentRecordID or? } + currentRecordID = debugId; prevLine = line; recordD.startCoords[coordId] = collectCoords(elem); recordL.startCoords[coordId] = collectCoords(elem); @@ -315,6 +334,8 @@ function reportResolve(method, debugId, length, coordId, elem, args){ var recordL = debugRecordsByLineNo[recordD.line]; recordD.method = method; recordL.method = method; + recordD.animated = true; + recordL.animated = true; var index = recordD.eventIndex; var location = traceEvents[index].location.first_line recordD.endCoords[coordId] = collectCoords(elem); @@ -326,11 +347,16 @@ function reportResolve(method, debugId, length, coordId, elem, args){ function end_program(){ //goes back and traces unanimated lines at the end of programs. + console.log("begin end_program"); var currentLine = -1; var tracedLine = -1; - while (currentIndex < traceEvents.length){ - currentLine = traceEvents[currentIndex].location.first_line; + while (currentRecordID < currentDebugId){ + console.log("loop end_program"); + + var currentRecord = debugRecordsByDebugId[currentRecordID]; + var currentIndex = currentRecord.eventIndex; var currentLocation = traceEvents[currentIndex].location; + currentLine = currentLocation.first_line; if (prevIndex != -1) { var prevLocation = traceEvents[prevIndex].location; @@ -346,6 +372,9 @@ function end_program(){ tracedLine = -1; } if(currentLine < prevLine){ + + console.log("currentLine: ", currentLine); + console.log('prevLine: ', prevLine); if (arrows[prevIndex] != null){ arrows[prevIndex]['after'] = {first: currentLocation, second: prevLocation}; @@ -360,19 +389,21 @@ function end_program(){ arrows[currentIndex] = {before: {first: currentLocation, second: prevLocation}, after : null}; } - view.arrow(view.paneid('left'), arrows, currentIndex);//should I pass in prevIndex and currentIndex or? + view.arrow(view.paneid('left'), arrows, currentIndex);//should I pass in prevIndex and currentRecordID or? } traceLine(currentLine); tracedLine = currentLine; prevLine = currentLine; prevIndex = currentIndex; - currentIndex += 1; + currentRecordID += 1; } if (tracedLine != -1){ untraceLine(tracedLine); + view.arrow(view.paneid('left'), arrows, -1); tracedLine = -1; } prevLine = -1; + console.log("end end_program"); } function errorAdvice(msg, text) { @@ -720,7 +751,7 @@ function stopButton(command) { lastRunTime = +new Date; if (pollTimer) { clearTimeout(pollTimer); pollTimer = null; } - currentIndex = 0; + currentRecordID = 0; prevIndex = -1; prevLocation = null; prevLine = -1; diff --git a/content/src/view.js b/content/src/view.js index 57f40f7f..f03e9572 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -314,6 +314,7 @@ function initializeSlider (traceevents, all_arrows, pane, debugRecordsByLineNo, } function createSlider(traceevents, all_arrows, pane, debugRecordsByLineNo, target) { + $(".scrubbermark").css("visibility", "visible"); if (traceevents[traceevents.length - 1].type == "enter" || traceevents[traceevents.length-1].type == "leave") { @@ -3384,6 +3385,8 @@ function arrow(pane, arrows, traceEventNum){ each key is a color for the arrow, and each value is a list of location pairs to draw an arrow on. */ + console.log('ARROW!'); + var startcoords = null; var endcoords = null; var offset_top = 0; From fc9429a1f4c3520632b9414f99c29e874bb8f784 Mon Sep 17 00:00:00 2001 From: calistenson Date: Mon, 27 Jul 2015 13:59:31 -0400 Subject: [PATCH 096/199] Fixed protractor --- content/src/debug.js | 21 ++++++--------------- content/src/view.js | 2 -- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/content/src/debug.js b/content/src/debug.js index 6608c1f4..0fb910b4 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -221,21 +221,20 @@ function reportSeeeval(method, debugId, length, coordId, elem, args){ function reportEnter(method, debugId, length, coordId, elem, args){ var recordD = debugRecordsByDebugId[debugId]; var recordL = debugRecordsByLineNo[recordD.line]; - recordD.method = method; - recordL.method = method; - recordD.args = args; - recordL.args = args; recordD.animated = false; recordL.animated = false; } function reportAppear(method, debugId, length, coordId, elem, args){ - console.log("currentRecordID: ", currentRecordID); + var recordD = debugRecordsByDebugId[debugId]; + var recordL = debugRecordsByLineNo[recordD.line]; + recordD.method = method; + recordL.method = method; + recordD.args = args; + recordL.args = args; - console.log("debugRecordsByDebugId: ", debugRecordsByDebugId); var currentRecord = debugRecordsByDebugId[currentRecordID]; - console.log("currentRecord: ", currentRecord); var currentIndex = currentRecord.eventIndex; var currentLocation = traceEvents[currentIndex].location; var currentLine = currentLocation.first_line; @@ -244,10 +243,8 @@ function reportAppear(method, debugId, length, coordId, elem, args){ stuckComplexity.moves += 1; - var recordD = debugRecordsByDebugId[debugId]; if (recordD) { if (!recordD.seeeval){ - var recordL = debugRecordsByLineNo[recordD.line]; var index = recordD.eventIndex; var line = traceEvents[index].location.first_line; var appear_location = traceEvents[index].location; @@ -347,11 +344,9 @@ function reportResolve(method, debugId, length, coordId, elem, args){ function end_program(){ //goes back and traces unanimated lines at the end of programs. - console.log("begin end_program"); var currentLine = -1; var tracedLine = -1; while (currentRecordID < currentDebugId){ - console.log("loop end_program"); var currentRecord = debugRecordsByDebugId[currentRecordID]; var currentIndex = currentRecord.eventIndex; @@ -372,9 +367,6 @@ function end_program(){ tracedLine = -1; } if(currentLine < prevLine){ - - console.log("currentLine: ", currentLine); - console.log('prevLine: ', prevLine); if (arrows[prevIndex] != null){ arrows[prevIndex]['after'] = {first: currentLocation, second: prevLocation}; @@ -403,7 +395,6 @@ function end_program(){ tracedLine = -1; } prevLine = -1; - console.log("end end_program"); } function errorAdvice(msg, text) { diff --git a/content/src/view.js b/content/src/view.js index 5b2e6c4e..86dae24e 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -3388,8 +3388,6 @@ function arrow(pane, arrows, traceEventNum){ each key is a color for the arrow, and each value is a list of location pairs to draw an arrow on. */ - console.log('ARROW!'); - var startcoords = null; var endcoords = null; var offset_top = 0; From 9110587914875f61290971c52b741ded5fefdd13 Mon Sep 17 00:00:00 2001 From: Amanda Date: Mon, 27 Jul 2015 16:17:16 -0400 Subject: [PATCH 097/199] Made styling changes and added number of steps --- content/src/editor.less | 67 ++++++++++++++++++++++++++--------------- content/src/view.js | 50 ++++++++++++++++-------------- 2 files changed, 70 insertions(+), 47 deletions(-) diff --git a/content/src/editor.less b/content/src/editor.less index de8f52fb..f51bf1d3 100644 --- a/content/src/editor.less +++ b/content/src/editor.less @@ -17,7 +17,25 @@ line-height: 16px; } } +#backButton { + position: relative; + left: 20%; + float: left; + display: inline-block; + vertical-align: middle; +} +#forwardButton { + position: relative; + left: 40%; + float: left; + display: inline-block; + vertical-align: middle; +} + +#label { + font-size: 50%; +} body { margin: 0; padding: 0; @@ -1111,66 +1129,65 @@ body#pencildoc #diigolet-csm { border: 2px solid #fffde7; } -.scrubber { +#slider { position: relative; top: 20%; left: 10%; width: 80%; } -.scrubber.ui-slider { - background: #d5cebc; - border: none; - border-radius: 0; +#slider.ui-slider-range { + height: 50px; } -.scrubber .ui-slider-tip { +#slider .ui-slider-tip { + width: 50px; visibility: visible; opacity: 1; top: -30px; } -.scrubber.ui-slider .ui-slider-handle { - top: -6px; - height: 16px; - width: 16px; +#slider.ui-slider .ui-slider-handle { + top: -6px; + height: 15px; + width: 15px; transform: rotateZ(360deg); } -.scrubber.ui-slider .ui-slider-handle.ui-state-hover, -.scrubber.ui-slider .ui-slider-handle.ui-state-focus, -.scrubber.ui-slider .ui-slider-handle.ui-state-active { +#slider.ui-slider .ui-slider-handle.ui-state-hover, +#slider.ui-slider .ui-slider-handle.ui-state-focus, +#slider.ui-slider .ui-slider-handle.ui-state-active { border-color: #172f38; } -.scrubber.ui-slider .ui-slider-pip .ui-slider-line { +#slider.ui-slider .ui-slider-pip .ui-slider-line { background: #d5cebc; transition: all 0.4s ease; } - -.scrubber.ui-slider.ui-slider-horizontal { + +#slider.ui-slider.ui-slider-horizontal { height: 6px; } - -.scrubber.ui-slider.ui-slider-horizontal .ui-slider-pip { + +#slider.ui-slider.ui-slider-horizontal .ui-slider-pip { top: 10px; } -.scrubber.ui-slider.ui-slider-horizontal .ui-slider-pip .ui-slider-line { +#slider.ui-slider.ui-slider-horizontal .ui-slider-pip .ui-slider-line { width: 2px; - height: 10px; + height: 5px; margin-left: -1px; } -.scrubber.ui-slider.ui-slider-horizontal .ui-slider-pip[class*=ui-slider-pip-selected] .ui-slider-line { - height: 20px; +#slider.ui-slider.ui-slider-horizontal .ui-slider-pip[class*=ui-slider-pip-selected] .ui-slider-line { + height: 10px; } -.scrubber.ui-slider.ui-slider-horizontal .ui-slider-pip.ui-slider-pip-inrange .ui-slider-line { - height: 12px; +#slider.ui-slider.ui-slider-horizontal .ui-slider-pip.ui-slider-pip-inrange .ui-slider-line { + height: 5px; } - + .texttoggle, .blocktoggle { position: absolute; width: 32px; diff --git a/content/src/view.js b/content/src/view.js index 86dae24e..efa27212 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -228,7 +228,7 @@ function paneid(position) { var sliderCreated = false; function removeSlider() { - $(".scrubber").remove(); + $(".scrubber").remove(); $("#backButton").remove(); $("#forwardButton").remove(); $(".scrubbermark").css("visibility", "hidden") @@ -254,6 +254,7 @@ function change(event, ui, traceevents, debugRecordsByLineNo, target, pane, all_ // Drawing arrows at each step in the slider arrow(pane, all_arrows, current_line); + $('#label').text('Step ' + ($("#slider").slider("value") + 1) + ' of ' + traceevents.length + ' Steps'); // ISSUE: CIRCULAR DEPENDICIES // display the protractor for that new line and highlight the selected line hideProtractor(paneid('right')); @@ -276,20 +277,26 @@ function initializeSlider (traceevents, all_arrows, pane, debugRecordsByLineNo, var backDiv = document.createElement('div'); var forwardDiv = document.createElement('div'); - + var sliderDiv = document.createElement('div'); + sliderDiv.id = 'slider'; // Append the newly created div for the slider to the panel at bottom $(".scrubbermark").append(div); - + $(".scrubber").append(sliderDiv); backDiv.innerHTML = ""; - $(".scrubbermark").append(backDiv); + $(".scrubber").append(backDiv); forwardDiv = document.createElement('div'); forwardDiv.innerHTML = ""; - - $(".scrubbermark").append(forwardDiv); + $(".scrubber").append(forwardDiv); + + var label = document.createElement('div'); + label.id = 'label'; + label.innerHTML = ""; + $(".scrubber").append(label); + // Code for the slider $(function() { - $(".scrubber").slider({ + $("#slider").slider({ min: 0, max: traceevents.length - 1, step: 1, @@ -304,16 +311,17 @@ function initializeSlider (traceevents, all_arrows, pane, debugRecordsByLineNo, } }) .slider("pips", { - first: "label", + first: "pip", rest: "pip", - last: "label", - labels: {"first": "1 step", "last": "1 step"} + last: "pip" }) .slider("float", { labels: linenoList, prefix: "Line " }) }); + $('#label').text('Step ' + ($("#slider").slider("value") + 1) + ' of ' + traceevents.length + ' Steps'); + } function createSlider(traceevents, all_arrows, pane, debugRecordsByLineNo, target) { @@ -324,9 +332,6 @@ function createSlider(traceevents, all_arrows, pane, debugRecordsByLineNo, targe traceevents.pop(); } - var firstLabel = (1).toString(); - var secondLabel = (traceevents.length).toString(); - // reset the list of line numbers before pushing a new number if (!sliderCreated) { linenoList = []; @@ -340,20 +345,20 @@ function createSlider(traceevents, all_arrows, pane, debugRecordsByLineNo, targe $('#backButton').on('click', function() { if (current_line != 0) { current_line--; - $(".scrubber").slider("value",current_line); + $("#slider").slider("value",current_line); } }); $('#forwardButton').on('click', function() { if (current_line != traceevents.length - 1) { current_line++ - $(".scrubber").slider("value", current_line); + $("#slider").slider("value", current_line); } }); // keep as variable so number of pips and maximum can be modified as events are pushed - var max = $( ".scrubber" ).slider("option", "max"); - var pips = $(".scrubber").slider("option", "pips"); + var max = $("#slider").slider("option", "max"); + var pips = $("#slider").slider("option", "pips"); // the slider has been created sliderCreated = true; @@ -361,17 +366,18 @@ function createSlider(traceevents, all_arrows, pane, debugRecordsByLineNo, targe // if the slider has already been created and events are pushed, modify existing slider if(sliderCreated){ - $(".scrubber").slider("option", "max", traceevents.length - 1) - $(".scrubber").slider("pips",{ - first: "label", + $("#slider").slider("option", "max", traceevents.length - 1) + $("#slider").slider("pips",{ + first: "pip", rest: "pip", - last: "label", - labels: {"first": firstLabel.concat(" Step"), "last": secondLabel.concat(" Steps")} + last: "pip" }) .slider("float", { labels: linenoList, prefix: "Line " }) + $('#label').text('Step ' + ($("#slider").slider("value") + 1) + ' of ' + traceevents.length + ' Steps'); + } } From b2f62dd800a35c67720eedabb1edb04177e1f55b Mon Sep 17 00:00:00 2001 From: calistenson Date: Mon, 27 Jul 2015 16:28:34 -0400 Subject: [PATCH 098/199] Added before and after arrow functionality to slider. Now arrows fade out one step instead of just showing up for one line. --- content/src/debug.js | 10 ++-- content/src/view.js | 132 ++++++++++++++++++++++++++++--------------- 2 files changed, 93 insertions(+), 49 deletions(-) diff --git a/content/src/debug.js b/content/src/debug.js index 0fb910b4..f456b946 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -280,7 +280,7 @@ function reportAppear(method, debugId, length, coordId, elem, args){ else{ arrows[currentIndex] = {before: {first: currentLocation, second: prevLocation}, after : null}; } - view.arrow(view.paneid('left'), arrows, currentRecordID);//should I pass in prevIndex and currentRecordID or? + view.arrow(view.paneid('left'), arrows, currentIndex, false);//should I pass in prevIndex and currentRecordID or? } traceLine(currentLine); tracedLine = currentLine; @@ -312,7 +312,7 @@ function reportAppear(method, debugId, length, coordId, elem, args){ else{ arrows[index] = {before: {first: currentLocation, second: prevLocation}, after : null}; } - view.arrow(view.paneid('left'), arrows, currentRecordID);//should I pass in prevIndex and currentRecordID or? + view.arrow(view.paneid('left'), arrows, currentIndex, false);//should I pass in prevIndex and currentRecordID or? } currentRecordID = debugId; prevLine = line; @@ -327,7 +327,7 @@ function reportResolve(method, debugId, length, coordId, elem, args){ var recordD = debugRecordsByDebugId[debugId]; if (recordD) { if (!recordD.seeeval){ - view.arrow(view.paneid('left'), arrows, -1); + view.arrow(view.paneid('left'), arrows, -1, false); var recordL = debugRecordsByLineNo[recordD.line]; recordD.method = method; recordL.method = method; @@ -381,7 +381,7 @@ function end_program(){ arrows[currentIndex] = {before: {first: currentLocation, second: prevLocation}, after : null}; } - view.arrow(view.paneid('left'), arrows, currentIndex);//should I pass in prevIndex and currentRecordID or? + view.arrow(view.paneid('left'), arrows, currentIndex, false);//should I pass in prevIndex and currentRecordID or? } traceLine(currentLine); tracedLine = currentLine; @@ -391,7 +391,7 @@ function end_program(){ } if (tracedLine != -1){ untraceLine(tracedLine); - view.arrow(view.paneid('left'), arrows, -1); + view.arrow(view.paneid('left'), arrows, -1, false); tracedLine = -1; } prevLine = -1; diff --git a/content/src/view.js b/content/src/view.js index 86dae24e..2bea9cf9 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -252,7 +252,7 @@ function change(event, ui, traceevents, debugRecordsByLineNo, target, pane, all_ var lineno = traceevents[current_line].location.first_line; // Drawing arrows at each step in the slider - arrow(pane, all_arrows, current_line); + arrow(pane, all_arrows, current_line, true); // ISSUE: CIRCULAR DEPENDICIES // display the protractor for that new line and highlight the selected line @@ -3383,18 +3383,26 @@ function curvedVertical(x1, y1, x2, y2) { //$(window).resize(..) event -function arrow(pane, arrows, traceEventNum){ +function arrow(pane, arrows, traceEventNum, slider_call){ /* note: we expect arrow_lines to be an array of key value pairs where each key is a color for the arrow, and each value is a list of location pairs to draw an arrow on. */ - var startcoords = null; - var endcoords = null; - var offset_top = 0; - var offset_left = 0; var arrow_data = arrows[traceEventNum]; + var startcoordsBefore = null; + var endcoordsBefore = null; + var offset_top_before = 0; + var offset_left_before = 0; var firstBeforeLoc = {}; var secondBeforeLoc = {}; + var firstAfterLoc = {}; + var secondAfterLoc = {}; + var startcoordsAfter = null; + var endcoordsAfter = null; + var offset_top_after = 0; + var offset_left_after = 0; + var before_arrowtext = ""; + var after_arrowtext = ""; $(".arrow").remove(); @@ -3403,71 +3411,107 @@ function arrow(pane, arrows, traceEventNum){ block_mode = true; if(!getPaneEditorBlockMode(pane)){block_mode = false;} } - - if (arrow_data){ if(arrow_data["before"]){ firstBeforeLoc = arrow_data['before']["first"]; secondBeforeLoc = arrow_data['before']['second']; } + if(arrow_data["after"]){ + firstAfterLoc = arrow_data["after"]["first"]; + secondAfterLoc = arrow_data["after"]["second"]; + } } if (firstBeforeLoc.first_line != undefined && secondBeforeLoc.first_line != undefined){ if (block_mode){ var dropletEditor = state.pane[pane].dropletEditor; - console.log("rows passed to droplet: ", firstBeforeLoc.first_line, secondBeforeLoc.first_line); - var startBounds = dropletEditor.getLineMetrics(firstBeforeLoc.first_line); - var endBounds = dropletEditor.getLineMetrics(secondBeforeLoc.first_line); - startcoords = {pageX : startBounds.bounds.x, pageY: startBounds.bounds.y}; - endcoords = {pageX : endBounds.bounds.x, pageY: endBounds.bounds.y}; - offset_top = startBounds.bounds.height - 30; - offset_left = Math.max(startBounds.bounds.width, endBounds.bounds.width) + 20; - } + var startBoundsBefore = dropletEditor.getLineMetrics(firstBeforeLoc.first_line); + var endBoundsBefore = dropletEditor.getLineMetrics(secondBeforeLoc.first_line); + startcoordsBefore = {pageX : startBoundsBefore.bounds.x, pageY: startBoundsBefore.bounds.y}; + endcoordsBefore = {pageX : endBoundsBefore.bounds.x, pageY: endBoundsBefore.bounds.y}; + offset_top_before = startBoundsBefore.bounds.height - 30; + offset_left_before = Math.max(startBoundsBefore.bounds.width, endBoundsBefore.bounds.width) + 20; + } else{ - offset_top = $(".editor").offset().top ; - offset_left = $(".editor").offset().left + 30; - startcoords = state.pane[pane].editor.renderer.textToScreenCoordinates((firstBeforeLoc.first_line), (firstBeforeLoc.last_column + 10)); - endcoords = state.pane[pane].editor.renderer.textToScreenCoordinates((secondBeforeLoc.first_line ), (secondBeforeLoc.last_column + 10)); + offset_top_before = $(".editor").offset().top ; + offset_left_before = $(".editor").offset().left + 30; + startcoordsBefore = state.pane[pane].editor.renderer.textToScreenCoordinates((firstBeforeLoc.first_line), (firstBeforeLoc.last_column + 10)); + endcoordsBefore = state.pane[pane].editor.renderer.textToScreenCoordinates((secondBeforeLoc.first_line ), (secondBeforeLoc.last_column + 10)); } if (Math.abs(secondBeforeLoc.first_line - firstBeforeLoc.first_line) > 1){ var x_val = 0; - if(startcoords.pageX > endcoords.pageX){ - x_val = startcoords.pageX; + if(startcoordsBefore.pageX > endcoordsBefore.pageX){ + x_val = startcoordsBefore.pageX; } else{ - x_val = endcoords.pageX; + x_val = endcoordsBefore.pageX; } + } + if (slider_call){ + before_arrowtext = " \ " + } + else{ + before_arrowtext = " \ " + } + } + if (firstAfterLoc.first_line != undefined && secondAfterLoc.first_line != undefined){ + if (block_mode){ + var startBoundsAfter= dropletEditor.getLineMetrics(firstAfterLoc.first_line); + var endBoundsAfter = dropletEditor.getLineMetrics(secondAfterLoc.first_line); + startcoordsAfter = {pageX : startBoundsAfter.bounds.x, pageY: startBoundsAfter.bounds.y}; + endcoordsAfter = {pageX : endBoundsAfter.bounds.x, pageY: endBoundsAfter.bounds.y}; + offset_top_after = startBoundsAfter.bounds.height - 30; + offset_left_after = Math.max(startBoundsAfter.bounds.width, endBoundsAfter.bounds.width) + 20; + } + else{ + offset_top_after = $(".editor").offset().top ; + offset_left_after = $(".editor").offset().left + 30; + startcoordsAfter = state.pane[pane].editor.renderer.textToScreenCoordinates((firstAfterLoc.first_line), (firstAfterLoc.last_column + 10)); + endcoordsAfter = state.pane[pane].editor.renderer.textToScreenCoordinates((secondAfterLoc.first_line ), (secondAfterLoc.last_column + 10)); + } + if (Math.abs(secondAfterLoc.first_line - firstAfterLoc.first_line) > 1){ + var x_val = 0; + if(startcoordsAfter.pageX > endcoordsAfter.pageX){ + x_val = startcoordsAfter.pageX; + } + else{ + x_val = endcoordsAfter.pageX; + } + } + after_arrowtext = " \ " + } - var text = " \ - \ - \ - \ - \ - \ - ";//stroke-width=3 - - var div = document.createElement('div'); - div.className = "arrow"; - div.innerHTML = text; - div.style.visibility = 'visible'; - div.style.position = "absolute"; - div.style.zIndex = "10"; - div.style.left = "0px"; - div.style.top = "0px"; + \ + \ + \ + \ + \ + \ + \ " + before_arrowtext + after_arrowtext + " "; + + var div = document.createElement('div'); + div.className = "arrow"; + div.innerHTML = text; + div.style.visibility = 'visible'; + div.style.position = "absolute"; + div.style.zIndex = "10"; + div.style.left = "0px"; + div.style.top = "0px"; - if (arrow_data){ - $(".editor").append(div); - } + if (arrow_data){ + $(".editor").append(div); } - } }; From 881e2ca95ba43eb13cb68b0b1d640e9c39a1dca2 Mon Sep 17 00:00:00 2001 From: calistenson Date: Mon, 27 Jul 2015 17:01:09 -0400 Subject: [PATCH 099/199] Configuring arrows to work with line hover highlighting. --- content/src/debug.js | 3 +++ content/src/view.js | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/content/src/debug.js b/content/src/debug.js index f456b946..b13e5d0b 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -697,6 +697,8 @@ view.on('parseerror', function(pane, err) { ////////////////////////////////////////////////////////////////////// view.on('entergutter', function(pane, lineno) { if (pane != view.paneid('left')) return; + var eventIndex = debugRecordsByLineNo[lineno].eventIndex; + view.arrow(view.paneid('left'), arrows, eventIndex, true); view.clearPaneEditorMarks(view.paneid('left'), 'debugfocus'); view.markPaneEditorLine(view.paneid('left'), lineno, 'debugfocus'); displayProtractorForRecord(debugRecordsByLineNo[lineno]); @@ -705,6 +707,7 @@ view.on('entergutter', function(pane, lineno) { view.on('leavegutter', function(pane, lineno) { view.clearPaneEditorMarks(view.paneid('left'), 'debugfocus'); view.hideProtractor(view.paneid('right')); + $(".editor").remove("arrow"); }); view.on('icehover', function(pane, ev) { diff --git a/content/src/view.js b/content/src/view.js index 2584940c..0a6782a7 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -3389,7 +3389,7 @@ function curvedVertical(x1, y1, x2, y2) { //$(window).resize(..) event -function arrow(pane, arrows, traceEventNum, slider_call){ +function arrow(pane, arrows, traceEventNum, show_fade){ /* note: we expect arrow_lines to be an array of key value pairs where each key is a color for the arrow, and each value is a list of location pairs to draw an arrow on. */ @@ -3457,7 +3457,7 @@ function arrow(pane, arrows, traceEventNum, slider_call){ x_val = endcoordsBefore.pageX; } } - if (slider_call){ + if (show_fade){ before_arrowtext = " \ " } From df62e7e2fd33d1dd024195a7751e88fb22f5cc19 Mon Sep 17 00:00:00 2001 From: Amanda Date: Mon, 27 Jul 2015 17:02:47 -0400 Subject: [PATCH 100/199] Fixed program edit --- content/src/debug.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/content/src/debug.js b/content/src/debug.js index f456b946..f8257d8d 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -23,7 +23,7 @@ var currentSourceMap = null; // v3 source map for currently-running instrument var traceEvents = []; // list of event location objects created by tracing events var stuckTime = null; // timestmp to detect stuck programs var arrows = {}; // keep track of arrows that appear in the program - +var programChanged = false; // whether user edited program while running // verification of complexity of stuck loop var stuckComplexity = { lines: 0, @@ -51,6 +51,7 @@ function bindframe(w) { traceEvents = []; screenshots = []; arrows = {}; + programChanged = false; currentRecordID = 1; currentDebugId = 0; prevIndex = -1; @@ -227,6 +228,7 @@ function reportEnter(method, debugId, length, coordId, elem, args){ function reportAppear(method, debugId, length, coordId, elem, args){ +if (!programChanged) { var recordD = debugRecordsByDebugId[debugId]; var recordL = debugRecordsByLineNo[recordD.line]; recordD.method = method; @@ -322,6 +324,7 @@ function reportAppear(method, debugId, length, coordId, elem, args){ } } } +} function reportResolve(method, debugId, length, coordId, elem, args){ var recordD = debugRecordsByDebugId[debugId]; @@ -838,6 +841,7 @@ view.on('stop', function() { view.on('delta', function(){ $(".arrow").remove(); //need to add code that stops animation!!! + programChanged = true; }); /////////////////////////////////////////////////////////////////////////// From 77b2715522e0ce9bc131cd78455dd3e4b4f1ad03 Mon Sep 17 00:00:00 2001 From: Amanda Date: Tue, 28 Jul 2015 09:07:37 -0400 Subject: [PATCH 101/199] Fixed text spacing issue --- content/src/editor.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/content/src/editor.less b/content/src/editor.less index f51bf1d3..67f09d73 100644 --- a/content/src/editor.less +++ b/content/src/editor.less @@ -34,6 +34,10 @@ } #label { + position: relative; + float: left; + left: 10%; + display: inline-block; font-size: 50%; } body { From 3dd95a445c7edcaee0ae628d35d2ea9c8de3cb56 Mon Sep 17 00:00:00 2001 From: calistenson Date: Tue, 28 Jul 2015 10:05:14 -0400 Subject: [PATCH 102/199] Connected arrows to line hovering --- content/src/debug.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/content/src/debug.js b/content/src/debug.js index b13e5d0b..14ae9556 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -281,6 +281,8 @@ function reportAppear(method, debugId, length, coordId, elem, args){ arrows[currentIndex] = {before: {first: currentLocation, second: prevLocation}, after : null}; } view.arrow(view.paneid('left'), arrows, currentIndex, false);//should I pass in prevIndex and currentRecordID or? + debugRecordsByLineNo[prevLine].eventIndex = prevIndex; + debugRecordsByLineNo[currentLine].eventIndex = currentIndex; } traceLine(currentLine); tracedLine = currentLine; @@ -313,6 +315,8 @@ function reportAppear(method, debugId, length, coordId, elem, args){ arrows[index] = {before: {first: currentLocation, second: prevLocation}, after : null}; } view.arrow(view.paneid('left'), arrows, currentIndex, false);//should I pass in prevIndex and currentRecordID or? + debugRecordsByLineNo[prevLine].eventIndex = prevIndex; + debugRecordsByLineNo[currentLine].eventIndex = currentIndex; } currentRecordID = debugId; prevLine = line; @@ -380,7 +384,8 @@ function end_program(){ else{ arrows[currentIndex] = {before: {first: currentLocation, second: prevLocation}, after : null}; } - + debugRecordsByLineNo[prevLine].eventIndex = prevIndex; + debugRecordsByLineNo[currentLine].eventIndex = currentIndex; view.arrow(view.paneid('left'), arrows, currentIndex, false);//should I pass in prevIndex and currentRecordID or? } traceLine(currentLine); From 20a3469fab70886caf0827390100b559a293280c Mon Sep 17 00:00:00 2001 From: Amanda Date: Tue, 28 Jul 2015 17:10:30 -0400 Subject: [PATCH 103/199] Fixed function error --- content/src/view.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/content/src/view.js b/content/src/view.js index 0a6782a7..5e469fd3 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -337,7 +337,10 @@ function createSlider(traceevents, all_arrows, pane, debugRecordsByLineNo, targe linenoList = []; } for (var i = 0; i < traceevents.length; i++) { - linenoList[i] = (traceevents[i].location.first_line) + linenoList[i] = (traceevents[i].location.first_line); + if (traceevents[i].type == "enter" || traceevents[i].type == "leave") { + traceevents.splice(i, 1); + } } // If slider hasn't been created and there are events being pushed, create slider. if (!sliderCreated && traceevents.length > 0) { From c029223a7fcf463bbdcae0ed7a97e2c08e725fea Mon Sep 17 00:00:00 2001 From: calistenson Date: Tue, 28 Jul 2015 17:11:18 -0400 Subject: [PATCH 104/199] attempting fix for functions in droplet --- content/src/debug.js | 2 ++ content/src/view.js | 48 +++++++++++++++++++++++++++++++------------- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/content/src/debug.js b/content/src/debug.js index d7b3ead7..dcf4808b 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -141,6 +141,7 @@ var debug = window.ide = { var record = {line: 0, eventIndex: null, startCoords: [], endCoords: [], method: "", data: "", seeeval:false}; traceEvents.push(event); + console.log("traceEvents:", traceEvents); currentEventIndex = traceEvents.length - 1; record.eventIndex = currentEventIndex; var lineno = traceEvents[currentEventIndex].location.first_line; @@ -705,6 +706,7 @@ view.on('parseerror', function(pane, err) { ////////////////////////////////////////////////////////////////////// view.on('entergutter', function(pane, lineno) { if (pane != view.paneid('left')) return; + console.log("debugRecordsByLineNo", debugRecordsByLineNo); var eventIndex = debugRecordsByLineNo[lineno].eventIndex; view.arrow(view.paneid('left'), arrows, eventIndex, true); view.clearPaneEditorMarks(view.paneid('left'), 'debugfocus'); diff --git a/content/src/view.js b/content/src/view.js index 0a6782a7..56982d77 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -3383,7 +3383,13 @@ function setupHpanelBox(box) { function curvedVertical(x1, y1, x2, y2) { var radius = Math.abs(y1 - y2); var line = []; - + console.log("radius: ", radius); + + x1 = parseFloat(x1); + y1 = parseFloat(y1); + x2 = parseFloat(x2); + y2 = parseFloat(y2); + console.log("xs and ys: ", x1, y1, x2, y2); return 'M'+ x1 + "," + y1 + " " + 'A'+ radius + "," + radius + " 1 0,1 " + x2 + "," + y2; } @@ -3409,6 +3415,7 @@ function arrow(pane, arrows, traceEventNum, show_fade){ var offset_left_after = 0; var before_arrowtext = ""; var after_arrowtext = ""; + var x_val = 0; $(".arrow").remove(); @@ -3431,19 +3438,23 @@ function arrow(pane, arrows, traceEventNum, show_fade){ if (firstBeforeLoc.first_line != undefined && secondBeforeLoc.first_line != undefined){ + console.log("firstBeforeLoc.first_line: ", firstBeforeLoc.first_line); + console.log('secondBeforeLoc.first_line: ', secondBeforeLoc.first_line); if (block_mode){ var dropletEditor = state.pane[pane].dropletEditor; - var startBoundsBefore = dropletEditor.getLineMetrics(firstBeforeLoc.first_line); - var endBoundsBefore = dropletEditor.getLineMetrics(secondBeforeLoc.first_line); + + var startBoundsBefore = dropletEditor.getLineMetrics(firstBeforeLoc.first_line - 1); + var endBoundsBefore = dropletEditor.getLineMetrics(secondBeforeLoc.first_line - 1); + console.log("startBoundsBefore: ", startBoundsBefore); + console.log("endBoundsBefore: ", endBoundsBefore); startcoordsBefore = {pageX : startBoundsBefore.bounds.x, pageY: startBoundsBefore.bounds.y}; endcoordsBefore = {pageX : endBoundsBefore.bounds.x, pageY: endBoundsBefore.bounds.y}; offset_top_before = startBoundsBefore.bounds.height - 30; offset_left_before = Math.max(startBoundsBefore.bounds.width, endBoundsBefore.bounds.width) + 20; - } else{ offset_top_before = $(".editor").offset().top ; - offset_left_before = $(".editor").offset().left + 30; + offset_left_before = $(".editor").offset().left + 50; startcoordsBefore = state.pane[pane].editor.renderer.textToScreenCoordinates((firstBeforeLoc.first_line), (firstBeforeLoc.last_column + 10)); endcoordsBefore = state.pane[pane].editor.renderer.textToScreenCoordinates((secondBeforeLoc.first_line ), (secondBeforeLoc.last_column + 10)); } @@ -3457,27 +3468,36 @@ function arrow(pane, arrows, traceEventNum, show_fade){ x_val = endcoordsBefore.pageX; } } + console.log("Start Coords: ", startcoordsBefore); + console.log("End Coords: ", endcoordsBefore); + console.log("curvedVertical result: ", curvedVertical(x_val + offset_left_before, (startcoordsBefore.pageY - offset_top_before), x_val + offset_left_before, (endcoordsBefore.pageY - offset_top_before))) + console.log("x_val: ", x_val); if (show_fade){ - before_arrowtext = " \ " + before_arrowtext = " \ " } else{ - before_arrowtext = " \ " + before_arrowtext = " \ " } } if (firstAfterLoc.first_line != undefined && secondAfterLoc.first_line != undefined){ + console.log("firstAfterLoc: ", firstAfterLoc); + console.log("secondAfterLoc: ", secondAfterLoc); if (block_mode){ - var startBoundsAfter= dropletEditor.getLineMetrics(firstAfterLoc.first_line); - var endBoundsAfter = dropletEditor.getLineMetrics(secondAfterLoc.first_line); + console.log("In block mode locations are: ", firstAfterLoc, secondAfterLoc); + var startBoundsAfter= dropletEditor.getLineMetrics(firstAfterLoc.first_line - 1); + var endBoundsAfter = dropletEditor.getLineMetrics(secondAfterLoc.first_line - 1); startcoordsAfter = {pageX : startBoundsAfter.bounds.x, pageY: startBoundsAfter.bounds.y}; endcoordsAfter = {pageX : endBoundsAfter.bounds.x, pageY: endBoundsAfter.bounds.y}; offset_top_after = startBoundsAfter.bounds.height - 30; offset_left_after = Math.max(startBoundsAfter.bounds.width, endBoundsAfter.bounds.width) + 20; + console.log("Start Coords: ", startcoordsAfter); + console.log("End Coords: ", endcoordsAfter); } else{ offset_top_after = $(".editor").offset().top ; - offset_left_after = $(".editor").offset().left + 30; + offset_left_after = $(".editor").offset().left + 50; startcoordsAfter = state.pane[pane].editor.renderer.textToScreenCoordinates((firstAfterLoc.first_line), (firstAfterLoc.last_column + 10)); endcoordsAfter = state.pane[pane].editor.renderer.textToScreenCoordinates((secondAfterLoc.first_line ), (secondAfterLoc.last_column + 10)); } @@ -3491,8 +3511,8 @@ function arrow(pane, arrows, traceEventNum, show_fade){ x_val = endcoordsAfter.pageX; } } - after_arrowtext = " \ " + after_arrowtext = " \ " } var text = "/lib/droplet.css"> /lib/jquery-ui-slider-pips.css"> +/lib/nouislider.css"> /lib/font-awesome.css"> /lib/tooltipster/css/tooltipster.css"> diff --git a/content/lib/nouislider.css b/content/lib/nouislider.css new file mode 100644 index 00000000..517ec621 --- /dev/null +++ b/content/lib/nouislider.css @@ -0,0 +1,162 @@ + +/* Functional styling; + * These styles are required for noUiSlider to function. + * You don't need to change these rules to apply your design. + */ +.noUi-target, +.noUi-target * { +-webkit-touch-callout: none; +-webkit-user-select: none; +-ms-touch-action: none; +-ms-user-select: none; +-moz-user-select: none; +-moz-box-sizing: border-box; + box-sizing: border-box; +} +.noUi-target { + position: relative; + direction: ltr; +} +.noUi-base { + width: 100%; + height: 100%; + position: relative; + z-index: 1; /* Fix 401 */ +} +.noUi-origin { + position: absolute; + right: 0; + top: 0; + left: 0; + bottom: 0; +} +.noUi-handle { + position: relative; + z-index: 1; +} +.noUi-stacking .noUi-handle { +/* This class is applied to the lower origin when + its values is > 50%. */ + z-index: 10; +} +.noUi-state-tap .noUi-origin { +-webkit-transition: left 0.3s, top 0.3s; + transition: left 0.3s, top 0.3s; +} +.noUi-state-drag * { + cursor: inherit !important; +} + +/* Painting and performance; + * Browsers can paint handles in their own layer. + */ +.noUi-base { + -webkit-transform: translate3d(0,0,0); + transform: translate3d(0,0,0); +} + +/* Slider size and handle placement; + */ +.noUi-horizontal { + height: 18px; +} +.noUi-horizontal .noUi-handle { + width: 34px; + height: 28px; + left: -17px; + top: -6px; +} +.noUi-vertical { + width: 18px; +} +.noUi-vertical .noUi-handle { + width: 28px; + height: 34px; + left: -6px; + top: -17px; +} + +/* Styling; + */ +.noUi-background { + background: #FAFAFA; + box-shadow: inset 0 1px 1px #f0f0f0; +} +.noUi-connect { + background: #3FB8AF; + box-shadow: inset 0 0 3px rgba(51,51,51,0.45); +-webkit-transition: background 450ms; + transition: background 450ms; +} +.noUi-origin { + border-radius: 2px; +} +.noUi-target { + border-radius: 4px; + border: 1px solid #D3D3D3; + box-shadow: inset 0 1px 1px #F0F0F0, 0 3px 6px -5px #BBB; +} +.noUi-target.noUi-connect { + box-shadow: inset 0 0 3px rgba(51,51,51,0.45), 0 3px 6px -5px #BBB; +} + +/* Handles and cursors; + */ +.noUi-dragable { + cursor: w-resize; +} +.noUi-vertical .noUi-dragable { + cursor: n-resize; +} +.noUi-handle { + border: 1px solid #D9D9D9; + border-radius: 3px; + background: #FFF; + cursor: default; + box-shadow: inset 0 0 1px #FFF, + inset 0 1px 7px #EBEBEB, + 0 3px 6px -3px #BBB; +} +.noUi-active { + box-shadow: inset 0 0 1px #FFF, + inset 0 1px 7px #DDD, + 0 3px 6px -3px #BBB; +} + +/* Handle stripes; + */ +.noUi-handle:before, +.noUi-handle:after { + content: ""; + display: block; + position: absolute; + height: 14px; + width: 1px; + background: #E8E7E6; + left: 14px; + top: 6px; +} +.noUi-handle:after { + left: 17px; +} +.noUi-vertical .noUi-handle:before, +.noUi-vertical .noUi-handle:after { + width: 14px; + height: 1px; + left: 6px; + top: 14px; +} +.noUi-vertical .noUi-handle:after { + top: 17px; +} + +/* Disabled state; + */ +[disabled].noUi-connect, +[disabled] .noUi-connect { + background: #B8B8B8; +} +[disabled].noUi-origin, +[disabled] .noUi-handle { + cursor: not-allowed; +} diff --git a/content/lib/nouislider.js b/content/lib/nouislider.js new file mode 100644 index 00000000..67ae7549 --- /dev/null +++ b/content/lib/nouislider.js @@ -0,0 +1,1629 @@ +/*! nouislider - 8.0.2 - 2015-07-06 13:22:09 */ + +/*jslint browser: true */ +/*jslint white: true */ + +(function (factory) { + + if ( typeof define === 'function' && define.amd ) { + + // AMD. Register as an anonymous module. + define([], factory); + + } else if ( typeof exports === 'object' ) { + + var fs = require('fs'); + + // Node/CommonJS + module.exports = factory(); + module.exports.css = function () { + return fs.readFileSync(__dirname + '/nouislider.min.css', 'utf8'); + }; + + } else { + + // Browser globals + window.noUiSlider = factory(); + } + +}(function( ){ + + 'use strict'; + + + // Removes duplicates from an array. + function unique(array) { + return array.filter(function(a){ + return !this[a] ? this[a] = true : false; + }, {}); + } + + // Round a value to the closest 'to'. + function closest ( value, to ) { + return Math.round(value / to) * to; + } + + // Current position of an element relative to the document. + function offset ( elem ) { + + var rect = elem.getBoundingClientRect(), + doc = elem.ownerDocument, + win = doc.defaultView || doc.parentWindow, + docElem = doc.documentElement, + xOff = win.pageXOffset; + + // getBoundingClientRect contains left scroll in Chrome on Android. + // I haven't found a feature detection that proves this. Worst case + // scenario on mis-match: the 'tap' feature on horizontal sliders breaks. + if ( /webkit.*Chrome.*Mobile/i.test(navigator.userAgent) ) { + xOff = 0; + } + + return { + top: rect.top + win.pageYOffset - docElem.clientTop, + left: rect.left + xOff - docElem.clientLeft + }; + } + + // Checks whether a value is numerical. + function isNumeric ( a ) { + return typeof a === 'number' && !isNaN( a ) && isFinite( a ); + } + + // Rounds a number to 7 supported decimals. + function accurateNumber( number ) { + var p = Math.pow(10, 7); + return Number((Math.round(number*p)/p).toFixed(7)); + } + + // Sets a class and removes it after [duration] ms. + function addClassFor ( element, className, duration ) { + addClass(element, className); + setTimeout(function(){ + removeClass(element, className); + }, duration); + } + + // Limits a value to 0 - 100 + function limit ( a ) { + return Math.max(Math.min(a, 100), 0); + } + + // Wraps a variable as an array, if it isn't one yet. + function asArray ( a ) { + return Array.isArray(a) ? a : [a]; + } + + // Counts decimals + function countDecimals ( numStr ) { + var pieces = numStr.split("."); + return pieces.length > 1 ? pieces[1].length : 0; + } + + // http://youmightnotneedjquery.com/#add_class + function addClass ( el, className ) { + if ( el.classList ) { + el.classList.add(className); + } else { + el.className += ' ' + className; + } + } + + // http://youmightnotneedjquery.com/#remove_class + function removeClass ( el, className ) { + if ( el.classList ) { + el.classList.remove(className); + } else { + el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); + } + } + + // http://youmightnotneedjquery.com/#has_class + function hasClass ( el, className ) { + if ( el.classList ) { + el.classList.contains(className); + } else { + new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className); + } + } + + + var + // Determine the events to bind. IE11 implements pointerEvents without + // a prefix, which breaks compatibility with the IE10 implementation. + /** @const */ + actions = window.navigator.pointerEnabled ? { + start: 'pointerdown', + move: 'pointermove', + end: 'pointerup' + } : window.navigator.msPointerEnabled ? { + start: 'MSPointerDown', + move: 'MSPointerMove', + end: 'MSPointerUp' + } : { + start: 'mousedown touchstart', + move: 'mousemove touchmove', + end: 'mouseup touchend' + }, + // Re-usable list of classes; + /** @const */ + Classes = [ +/* 0 */ 'noUi-target' +/* 1 */ ,'noUi-base' +/* 2 */ ,'noUi-origin' +/* 3 */ ,'noUi-handle' +/* 4 */ ,'noUi-horizontal' +/* 5 */ ,'noUi-vertical' +/* 6 */ ,'noUi-background' +/* 7 */ ,'noUi-connect' +/* 8 */ ,'noUi-ltr' +/* 9 */ ,'noUi-rtl' +/* 10 */ ,'noUi-dragable' +/* 11 */ ,'' +/* 12 */ ,'noUi-state-drag' +/* 13 */ ,'' +/* 14 */ ,'noUi-state-tap' +/* 15 */ ,'noUi-active' +/* 16 */ ,'' +/* 17 */ ,'noUi-stacking' + ]; + + +// Value calculation + + // Determine the size of a sub-range in relation to a full range. + function subRangeRatio ( pa, pb ) { + return (100 / (pb - pa)); + } + + // (percentage) How many percent is this value of this range? + function fromPercentage ( range, value ) { + return (value * 100) / ( range[1] - range[0] ); + } + + // (percentage) Where is this value on this range? + function toPercentage ( range, value ) { + return fromPercentage( range, range[0] < 0 ? + value + Math.abs(range[0]) : + value - range[0] ); + } + + // (value) How much is this percentage on this range? + function isPercentage ( range, value ) { + return ((value * ( range[1] - range[0] )) / 100) + range[0]; + } + + +// Range conversion + + function getJ ( value, arr ) { + + var j = 1; + + while ( value >= arr[j] ){ + j += 1; + } + + return j; + } + + // (percentage) Input a value, find where, on a scale of 0-100, it applies. + function toStepping ( xVal, xPct, value ) { + + if ( value >= xVal.slice(-1)[0] ){ + return 100; + } + + var j = getJ( value, xVal ), va, vb, pa, pb; + + va = xVal[j-1]; + vb = xVal[j]; + pa = xPct[j-1]; + pb = xPct[j]; + + return pa + (toPercentage([va, vb], value) / subRangeRatio (pa, pb)); + } + + // (value) Input a percentage, find where it is on the specified range. + function fromStepping ( xVal, xPct, value ) { + + // There is no range group that fits 100 + if ( value >= 100 ){ + return xVal.slice(-1)[0]; + } + + var j = getJ( value, xPct ), va, vb, pa, pb; + + va = xVal[j-1]; + vb = xVal[j]; + pa = xPct[j-1]; + pb = xPct[j]; + + return isPercentage([va, vb], (value - pa) * subRangeRatio (pa, pb)); + } + + // (percentage) Get the step that applies at a certain value. + function getStep ( xPct, xSteps, snap, value ) { + + if ( value === 100 ) { + return value; + } + + var j = getJ( value, xPct ), a, b; + + // If 'snap' is set, steps are used as fixed points on the slider. + if ( snap ) { + + a = xPct[j-1]; + b = xPct[j]; + + // Find the closest position, a or b. + if ((value - a) > ((b-a)/2)){ + return b; + } + + return a; + } + + if ( !xSteps[j-1] ){ + return value; + } + + return xPct[j-1] + closest( + value - xPct[j-1], + xSteps[j-1] + ); + } + + +// Entry parsing + + function handleEntryPoint ( index, value, that ) { + + var percentage; + + // Wrap numerical input in an array. + if ( typeof value === "number" ) { + value = [value]; + } + + // Reject any invalid input, by testing whether value is an array. + if ( Object.prototype.toString.call( value ) !== '[object Array]' ){ + throw new Error("noUiSlider: 'range' contains invalid value."); + } + + // Covert min/max syntax to 0 and 100. + if ( index === 'min' ) { + percentage = 0; + } else if ( index === 'max' ) { + percentage = 100; + } else { + percentage = parseFloat( index ); + } + + // Check for correct input. + if ( !isNumeric( percentage ) || !isNumeric( value[0] ) ) { + throw new Error("noUiSlider: 'range' value isn't numeric."); + } + + // Store values. + that.xPct.push( percentage ); + that.xVal.push( value[0] ); + + // NaN will evaluate to false too, but to keep + // logging clear, set step explicitly. Make sure + // not to override the 'step' setting with false. + if ( !percentage ) { + if ( !isNaN( value[1] ) ) { + that.xSteps[0] = value[1]; + } + } else { + that.xSteps.push( isNaN(value[1]) ? false : value[1] ); + } + } + + function handleStepPoint ( i, n, that ) { + + // Ignore 'false' stepping. + if ( !n ) { + return true; + } + + // Factor to range ratio + that.xSteps[i] = fromPercentage([ + that.xVal[i] + ,that.xVal[i+1] + ], n) / subRangeRatio ( + that.xPct[i], + that.xPct[i+1] ); + } + + +// Interface + + // The interface to Spectrum handles all direction-based + // conversions, so the above values are unaware. + + function Spectrum ( entry, snap, direction, singleStep ) { + + this.xPct = []; + this.xVal = []; + this.xSteps = [ singleStep || false ]; + this.xNumSteps = [ false ]; + + this.snap = snap; + this.direction = direction; + + var index, ordered = [ /* [0, 'min'], [1, '50%'], [2, 'max'] */ ]; + + // Map the object keys to an array. + for ( index in entry ) { + if ( entry.hasOwnProperty(index) ) { + ordered.push([entry[index], index]); + } + } + + // Sort all entries by value (numeric sort). + ordered.sort(function(a, b) { return a[0] - b[0]; }); + + // Convert all entries to subranges. + for ( index = 0; index < ordered.length; index++ ) { + handleEntryPoint(ordered[index][1], ordered[index][0], this); + } + + // Store the actual step values. + // xSteps is sorted in the same order as xPct and xVal. + this.xNumSteps = this.xSteps.slice(0); + + // Convert all numeric steps to the percentage of the subrange they represent. + for ( index = 0; index < this.xNumSteps.length; index++ ) { + handleStepPoint(index, this.xNumSteps[index], this); + } + } + + Spectrum.prototype.getMargin = function ( value ) { + return this.xPct.length === 2 ? fromPercentage(this.xVal, value) : false; + }; + + Spectrum.prototype.toStepping = function ( value ) { + + value = toStepping( this.xVal, this.xPct, value ); + + // Invert the value if this is a right-to-left slider. + if ( this.direction ) { + value = 100 - value; + } + + return value; + }; + + Spectrum.prototype.fromStepping = function ( value ) { + + // Invert the value if this is a right-to-left slider. + if ( this.direction ) { + value = 100 - value; + } + + return accurateNumber(fromStepping( this.xVal, this.xPct, value )); + }; + + Spectrum.prototype.getStep = function ( value ) { + + // Find the proper step for rtl sliders by search in inverse direction. + // Fixes issue #262. + if ( this.direction ) { + value = 100 - value; + } + + value = getStep(this.xPct, this.xSteps, this.snap, value ); + + if ( this.direction ) { + value = 100 - value; + } + + return value; + }; + + Spectrum.prototype.getApplicableStep = function ( value ) { + + // If the value is 100%, return the negative step twice. + var j = getJ(value, this.xPct), offset = value === 100 ? 2 : 1; + return [this.xNumSteps[j-2], this.xVal[j-offset], this.xNumSteps[j-offset]]; + }; + + // Outside testing + Spectrum.prototype.convert = function ( value ) { + return this.getStep(this.toStepping(value)); + }; + +/* Every input option is tested and parsed. This'll prevent + endless validation in internal methods. These tests are + structured with an item for every option available. An + option can be marked as required by setting the 'r' flag. + The testing function is provided with three arguments: + - The provided value for the option; + - A reference to the options object; + - The name for the option; + + The testing function returns false when an error is detected, + or true when everything is OK. It can also modify the option + object, to make sure all values can be correctly looped elsewhere. */ + + var defaultFormatter = { 'to': function( value ){ + return value.toFixed(2); + }, 'from': Number }; + + function testStep ( parsed, entry ) { + + if ( !isNumeric( entry ) ) { + throw new Error("noUiSlider: 'step' is not numeric."); + } + + // The step option can still be used to set stepping + // for linear sliders. Overwritten if set in 'range'. + parsed.singleStep = entry; + } + + function testRange ( parsed, entry ) { + + // Filter incorrect input. + if ( typeof entry !== 'object' || Array.isArray(entry) ) { + throw new Error("noUiSlider: 'range' is not an object."); + } + + // Catch missing start or end. + if ( entry.min === undefined || entry.max === undefined ) { + throw new Error("noUiSlider: Missing 'min' or 'max' in 'range'."); + } + + parsed.spectrum = new Spectrum(entry, parsed.snap, parsed.dir, parsed.singleStep); + } + + function testStart ( parsed, entry ) { + + entry = asArray(entry); + + // Validate input. Values aren't tested, as the public .val method + // will always provide a valid location. + if ( !Array.isArray( entry ) || !entry.length || entry.length > 2 ) { + throw new Error("noUiSlider: 'start' option is incorrect."); + } + + // Store the number of handles. + parsed.handles = entry.length; + + // When the slider is initialized, the .val method will + // be called with the start options. + parsed.start = entry; + } + + function testSnap ( parsed, entry ) { + + // Enforce 100% stepping within subranges. + parsed.snap = entry; + + if ( typeof entry !== 'boolean' ){ + throw new Error("noUiSlider: 'snap' option must be a boolean."); + } + } + + function testAnimate ( parsed, entry ) { + + // Enforce 100% stepping within subranges. + parsed.animate = entry; + + if ( typeof entry !== 'boolean' ){ + throw new Error("noUiSlider: 'animate' option must be a boolean."); + } + } + + function testConnect ( parsed, entry ) { + + if ( entry === 'lower' && parsed.handles === 1 ) { + parsed.connect = 1; + } else if ( entry === 'upper' && parsed.handles === 1 ) { + parsed.connect = 2; + } else if ( entry === true && parsed.handles === 2 ) { + parsed.connect = 3; + } else if ( entry === false ) { + parsed.connect = 0; + } else { + throw new Error("noUiSlider: 'connect' option doesn't match handle count."); + } + } + + function testOrientation ( parsed, entry ) { + + // Set orientation to an a numerical value for easy + // array selection. + switch ( entry ){ + case 'horizontal': + parsed.ort = 0; + break; + case 'vertical': + parsed.ort = 1; + break; + default: + throw new Error("noUiSlider: 'orientation' option is invalid."); + } + } + + function testMargin ( parsed, entry ) { + + if ( !isNumeric(entry) ){ + throw new Error("noUiSlider: 'margin' option must be numeric."); + } + + parsed.margin = parsed.spectrum.getMargin(entry); + + if ( !parsed.margin ) { + throw new Error("noUiSlider: 'margin' option is only supported on linear sliders."); + } + } + + function testLimit ( parsed, entry ) { + + if ( !isNumeric(entry) ){ + throw new Error("noUiSlider: 'limit' option must be numeric."); + } + + parsed.limit = parsed.spectrum.getMargin(entry); + + if ( !parsed.limit ) { + throw new Error("noUiSlider: 'limit' option is only supported on linear sliders."); + } + } + + function testDirection ( parsed, entry ) { + + // Set direction as a numerical value for easy parsing. + // Invert connection for RTL sliders, so that the proper + // handles get the connect/background classes. + switch ( entry ) { + case 'ltr': + parsed.dir = 0; + break; + case 'rtl': + parsed.dir = 1; + parsed.connect = [0,2,1,3][parsed.connect]; + break; + default: + throw new Error("noUiSlider: 'direction' option was not recognized."); + } + } + + function testBehaviour ( parsed, entry ) { + + // Make sure the input is a string. + if ( typeof entry !== 'string' ) { + throw new Error("noUiSlider: 'behaviour' must be a string containing options."); + } + + // Check if the string contains any keywords. + // None are required. + var tap = entry.indexOf('tap') >= 0, + drag = entry.indexOf('drag') >= 0, + fixed = entry.indexOf('fixed') >= 0, + snap = entry.indexOf('snap') >= 0; + + parsed.events = { + tap: tap || snap, + drag: drag, + fixed: fixed, + snap: snap + }; + } + + function testFormat ( parsed, entry ) { + + parsed.format = entry; + + // Any object with a to and from method is supported. + if ( typeof entry.to === 'function' && typeof entry.from === 'function' ) { + return true; + } + + throw new Error( "noUiSlider: 'format' requires 'to' and 'from' methods."); + } + + // Test all developer settings and parse to assumption-safe values. + function testOptions ( options ) { + + var parsed = { + margin: 0, + limit: 0, + animate: true, + format: defaultFormatter + }, tests; + + // Tests are executed in the order they are presented here. + tests = { + 'step': { r: false, t: testStep }, + 'start': { r: true, t: testStart }, + 'connect': { r: true, t: testConnect }, + 'direction': { r: true, t: testDirection }, + 'snap': { r: false, t: testSnap }, + 'animate': { r: false, t: testAnimate }, + 'range': { r: true, t: testRange }, + 'orientation': { r: false, t: testOrientation }, + 'margin': { r: false, t: testMargin }, + 'limit': { r: false, t: testLimit }, + 'behaviour': { r: true, t: testBehaviour }, + 'format': { r: false, t: testFormat } + }; + + var defaults = { + 'connect': false, + 'direction': 'ltr', + 'behaviour': 'tap', + 'orientation': 'horizontal' + }; + + // Set defaults where applicable. + Object.keys(defaults).forEach(function ( name ) { + if ( options[name] === undefined ) { + options[name] = defaults[name]; + } + }); + + // Run all options through a testing mechanism to ensure correct + // input. It should be noted that options might get modified to + // be handled properly. E.g. wrapping integers in arrays. + Object.keys(tests).forEach(function( name ){ + + var test = tests[name]; + + // If the option isn't set, but it is required, throw an error. + if ( options[name] === undefined ) { + + if ( test.r ) { + throw new Error("noUiSlider: '" + name + "' is required."); + } + + return true; + } + + test.t( parsed, options[name] ); + }); + + // Forward pips options + parsed.pips = options.pips; + + // Pre-define the styles. + parsed.style = parsed.ort ? 'top' : 'left'; + + return parsed; + } + + + // Delimit proposed values for handle positions. + function getPositions ( a, b, delimit ) { + + // Add movement to current position. + var c = a + b[0], d = a + b[1]; + + // Only alter the other position on drag, + // not on standard sliding. + if ( delimit ) { + if ( c < 0 ) { + d += Math.abs(c); + } + if ( d > 100 ) { + c -= ( d - 100 ); + } + + // Limit values to 0 and 100. + return [limit(c), limit(d)]; + } + + return [c,d]; + } + + // Provide a clean event with standardized offset values. + function fixEvent ( e ) { + + // Prevent scrolling and panning on touch events, while + // attempting to slide. The tap event also depends on this. + e.preventDefault(); + + // Filter the event to register the type, which can be + // touch, mouse or pointer. Offset changes need to be + // made on an event specific basis. + var touch = e.type.indexOf('touch') === 0, + mouse = e.type.indexOf('mouse') === 0, + pointer = e.type.indexOf('pointer') === 0, + x,y, event = e; + + // IE10 implemented pointer events with a prefix; + if ( e.type.indexOf('MSPointer') === 0 ) { + pointer = true; + } + + if ( touch ) { + // noUiSlider supports one movement at a time, + // so we can select the first 'changedTouch'. + x = e.changedTouches[0].pageX; + y = e.changedTouches[0].pageY; + } + + if ( mouse || pointer ) { + x = e.clientX + window.pageXOffset; + y = e.clientY + window.pageYOffset; + } + + event.points = [x, y]; + event.cursor = mouse || pointer; // Fix #435 + + return event; + } + + // Append a handle to the base. + function addHandle ( direction, index ) { + + var origin = document.createElement('div'), + handle = document.createElement('div'), + additions = [ '-lower', '-upper' ]; + + if ( direction ) { + additions.reverse(); + } + + addClass(handle, Classes[3]); + addClass(handle, Classes[3] + additions[index]); + + addClass(origin, Classes[2]); + origin.appendChild(handle); + + return origin; + } + + // Add the proper connection classes. + function addConnection ( connect, target, handles ) { + + // Apply the required connection classes to the elements + // that need them. Some classes are made up for several + // segments listed in the class list, to allow easy + // renaming and provide a minor compression benefit. + switch ( connect ) { + case 1: addClass(target, Classes[7]); + addClass(handles[0], Classes[6]); + break; + case 3: addClass(handles[1], Classes[6]); + /* falls through */ + case 2: addClass(handles[0], Classes[7]); + /* falls through */ + case 0: addClass(target, Classes[6]); + break; + } + } + + // Add handles to the slider base. + function addHandles ( nrHandles, direction, base ) { + + var index, handles = []; + + // Append handles. + for ( index = 0; index < nrHandles; index += 1 ) { + + // Keep a list of all added handles. + handles.push( base.appendChild(addHandle( direction, index )) ); + } + + return handles; + } + + // Initialize a single slider. + function addSlider ( direction, orientation, target ) { + + // Apply classes and data to the target. + addClass(target, Classes[0]); + addClass(target, Classes[8 + direction]); + addClass(target, Classes[4 + orientation]); + + var div = document.createElement('div'); + addClass(div, Classes[1]); + target.appendChild(div); + return div; + } + + +function closure ( target, options ){ + + // All variables local to 'closure' are prefixed with 'scope_' + var scope_Target = target, + scope_Locations = [-1, -1], + scope_Base, + scope_Handles, + scope_Spectrum = options.spectrum, + scope_Values = [], + scope_Events = {}; + + + function getGroup ( mode, values, stepped ) { + + // Use the range. + if ( mode === 'range' || mode === 'steps' ) { + return scope_Spectrum.xVal; + } + + if ( mode === 'count' ) { + + // Divide 0 - 100 in 'count' parts. + var spread = ( 100 / (values-1) ), v, i = 0; + values = []; + + // List these parts and have them handled as 'positions'. + while ((v=i++*spread) <= 100 ) { + values.push(v); + } + + mode = 'positions'; + } + + if ( mode === 'positions' ) { + + // Map all percentages to on-range values. + return values.map(function( value ){ + return scope_Spectrum.fromStepping( stepped ? scope_Spectrum.getStep( value ) : value ); + }); + } + + if ( mode === 'values' ) { + + // If the value must be stepped, it needs to be converted to a percentage first. + if ( stepped ) { + + return values.map(function( value ){ + + // Convert to percentage, apply step, return to value. + return scope_Spectrum.fromStepping( scope_Spectrum.getStep( scope_Spectrum.toStepping( value ) ) ); + }); + + } + + // Otherwise, we can simply use the values. + return values; + } + } + + function generateSpread ( density, mode, group ) { + + var originalSpectrumDirection = scope_Spectrum.direction, + indexes = {}, + firstInRange = scope_Spectrum.xVal[0], + lastInRange = scope_Spectrum.xVal[scope_Spectrum.xVal.length-1], + ignoreFirst = false, + ignoreLast = false, + prevPct = 0; + + // This function loops the spectrum in an ltr linear fashion, + // while the toStepping method is direction aware. Trick it into + // believing it is ltr. + scope_Spectrum.direction = 0; + + // Create a copy of the group, sort it and filter away all duplicates. + group = unique(group.slice().sort(function(a, b){ return a - b; })); + + // Make sure the range starts with the first element. + if ( group[0] !== firstInRange ) { + group.unshift(firstInRange); + ignoreFirst = true; + } + + // Likewise for the last one. + if ( group[group.length - 1] !== lastInRange ) { + group.push(lastInRange); + ignoreLast = true; + } + + group.forEach(function ( current, index ) { + + // Get the current step and the lower + upper positions. + var step, i, q, + low = current, + high = group[index+1], + newPct, pctDifference, pctPos, type, + steps, realSteps, stepsize; + + // When using 'steps' mode, use the provided steps. + // Otherwise, we'll step on to the next subrange. + if ( mode === 'steps' ) { + step = scope_Spectrum.xNumSteps[ index ]; + } + + // Default to a 'full' step. + if ( !step ) { + step = high-low; + } + + // Low can be 0, so test for false. If high is undefined, + // we are at the last subrange. Index 0 is already handled. + if ( low === false || high === undefined ) { + return; + } + + // Find all steps in the subrange. + for ( i = low; i <= high; i += step ) { + + // Get the percentage value for the current step, + // calculate the size for the subrange. + newPct = scope_Spectrum.toStepping( i ); + pctDifference = newPct - prevPct; + + steps = pctDifference / density; + realSteps = Math.round(steps); + + // This ratio represents the ammount of percentage-space a point indicates. + // For a density 1 the points/percentage = 1. For density 2, that percentage needs to be re-devided. + // Round the percentage offset to an even number, then divide by two + // to spread the offset on both sides of the range. + stepsize = pctDifference/realSteps; + + // Divide all points evenly, adding the correct number to this subrange. + // Run up to <= so that 100% gets a point, event if ignoreLast is set. + for ( q = 1; q <= realSteps; q += 1 ) { + + // The ratio between the rounded value and the actual size might be ~1% off. + // Correct the percentage offset by the number of points + // per subrange. density = 1 will result in 100 points on the + // full range, 2 for 50, 4 for 25, etc. + pctPos = prevPct + ( q * stepsize ); + indexes[pctPos.toFixed(5)] = ['x', 0]; + } + + // Determine the point type. + type = (group.indexOf(i) > -1) ? 1 : ( mode === 'steps' ? 2 : 0 ); + + // Enforce the 'ignoreFirst' option by overwriting the type for 0. + if ( !index && ignoreFirst ) { + type = 0; + } + + if ( !(i === high && ignoreLast)) { + // Mark the 'type' of this point. 0 = plain, 1 = real value, 2 = step value. + indexes[newPct.toFixed(5)] = [i, type]; + } + + // Update the percentage count. + prevPct = newPct; + } + }); + + // Reset the spectrum. + scope_Spectrum.direction = originalSpectrumDirection; + + return indexes; + } + + function addMarking ( spread, filterFunc, formatter ) { + + var style = ['horizontal', 'vertical'][options.ort], + element = document.createElement('div'); + + addClass(element, 'noUi-pips'); + addClass(element, 'noUi-pips-' + style); + + function getSize( type ){ + return [ '-normal', '-large', '-sub' ][type]; + } + + function getTags( offset, source, values ) { + return 'class="' + source + ' ' + + source + '-' + style + ' ' + + source + getSize(values[1]) + + '" style="' + options.style + ': ' + offset + '%"'; + } + + function addSpread ( offset, values ){ + + if ( scope_Spectrum.direction ) { + offset = 100 - offset; + } + + // Apply the filter function, if it is set. + values[1] = (values[1] && filterFunc) ? filterFunc(values[0], values[1]) : values[1]; + + // Add a marker for every point + element.innerHTML += '
'; + + // Values are only appended for points marked '1' or '2'. + if ( values[1] ) { + element.innerHTML += '
' + formatter.to(values[0]) + '
'; + } + } + + // Append all points. + Object.keys(spread).forEach(function(a){ + addSpread(a, spread[a]); + }); + + return element; + } + + function pips ( grid ) { + + var mode = grid.mode, + density = grid.density || 1, + filter = grid.filter || false, + values = grid.values || false, + stepped = grid.stepped || false, + group = getGroup( mode, values, stepped ), + spread = generateSpread( density, mode, group ), + format = grid.format || { + to: Math.round + }; + + return scope_Target.appendChild(addMarking( + spread, + filter, + format + )); + } + + + // Shorthand for base dimensions. + function baseSize ( ) { + return scope_Base['offset' + ['Width', 'Height'][options.ort]]; + } + + // External event handling + function fireEvent ( event, handleNumber ) { + + if ( handleNumber !== undefined ) { + handleNumber = Math.abs(handleNumber - options.dir); + } + + Object.keys(scope_Events).forEach(function( targetEvent ) { + + var eventType = targetEvent.split('.')[0]; + + if ( event === eventType ) { + scope_Events[targetEvent].forEach(function( callback ) { + // .reverse is in place + // Return values as array, so arg_1[arg_2] is always valid. + callback( asArray(valueGet()), handleNumber, inSliderOrder(Array.prototype.slice.call(scope_Values)) ); + }); + } + }); + } + + // Returns the input array, respecting the slider direction configuration. + function inSliderOrder ( values ) { + + // If only one handle is used, return a single value. + if ( values.length === 1 ){ + return values[0]; + } + + if ( options.dir ) { + return values.reverse(); + } + + return values; + } + + + // Handler for attaching events trough a proxy. + function attach ( events, element, callback, data ) { + + // This function can be used to 'filter' events to the slider. + // element is a node, not a nodeList + + var method = function ( e ){ + + if ( scope_Target.hasAttribute('disabled') ) { + return false; + } + + // Stop if an active 'tap' transition is taking place. + if ( hasClass(scope_Target, Classes[14]) ) { + return false; + } + + e = fixEvent(e); + + // Ignore right or middle clicks on start #454 + if ( events === actions.start && e.buttons !== undefined && e.buttons > 1 ) { + return false; + } + + e.calcPoint = e.points[ options.ort ]; + + // Call the event handler with the event [ and additional data ]. + callback ( e, data ); + + }, methods = []; + + // Bind a closure on the target for every event type. + events.split(' ').forEach(function( eventName ){ + element.addEventListener(eventName, method, false); + methods.push([eventName, method]); + }); + + return methods; + } + + // Handle movement on document for handle and range drag. + function move ( event, data ) { + + var handles = data.handles || scope_Handles, positions, state = false, + proposal = ((event.calcPoint - data.start) * 100) / baseSize(), + handleNumber = handles[0] === scope_Handles[0] ? 0 : 1, i; + + // Calculate relative positions for the handles. + positions = getPositions( proposal, data.positions, handles.length > 1); + + state = setHandle ( handles[0], positions[handleNumber], handles.length === 1 ); + + if ( handles.length > 1 ) { + + state = setHandle ( handles[1], positions[handleNumber?0:1], false ) || state; + + if ( state ) { + // fire for both handles + for ( i = 0; i < data.handles.length; i++ ) { + fireEvent('slide', i); + } + } + } else if ( state ) { + // Fire for a single handle + fireEvent('slide', handleNumber); + } + } + + // Unbind move events on document, call callbacks. + function end ( event, data ) { + + // The handle is no longer active, so remove the class. + var active = scope_Base.getElementsByClassName(Classes[15]), + handleNumber = data.handles[0] === scope_Handles[0] ? 0 : 1; + + if ( active.length ) { + removeClass(active[0], Classes[15]); + } + + // Remove cursor styles and text-selection events bound to the body. + if ( event.cursor ) { + document.body.style.cursor = ''; + document.body.removeEventListener('selectstart', document.body.noUiListener); + } + + var d = document.documentElement; + + // Unbind the move and end events, which are added on 'start'. + d.noUiListeners.forEach(function( c ) { + d.removeEventListener(c[0], c[1]); + }); + + // Remove dragging class. + removeClass(scope_Target, Classes[12]); + + // Fire the change and set events. + fireEvent('set', handleNumber); + fireEvent('change', handleNumber); + } + + // Bind move events on document. + function start ( event, data ) { + + var d = document.documentElement; + + // Mark the handle as 'active' so it can be styled. + if ( data.handles.length === 1 ) { + addClass(data.handles[0].children[0], Classes[15]); + + // Support 'disabled' handles + if ( data.handles[0].hasAttribute('disabled') ) { + return false; + } + } + + // A drag should never propagate up to the 'tap' event. + event.stopPropagation(); + + // Attach the move and end events. + var moveEvent = attach(actions.move, d, move, { + start: event.calcPoint, + handles: data.handles, + positions: [ + scope_Locations[0], + scope_Locations[scope_Handles.length - 1] + ] + }), endEvent = attach(actions.end, d, end, { + handles: data.handles + }); + + d.noUiListeners = moveEvent.concat(endEvent); + + // Text selection isn't an issue on touch devices, + // so adding cursor styles can be skipped. + if ( event.cursor ) { + + // Prevent the 'I' cursor and extend the range-drag cursor. + document.body.style.cursor = getComputedStyle(event.target).cursor; + + // Mark the target with a dragging state. + if ( scope_Handles.length > 1 ) { + addClass(scope_Target, Classes[12]); + } + + var f = function(){ + return false; + }; + + document.body.noUiListener = f; + + // Prevent text selection when dragging the handles. + document.body.addEventListener('selectstart', f, false); + } + } + + // Move closest handle to tapped location. + function tap ( event ) { + + var location = event.calcPoint, total = 0, handleNumber, to; + + // The tap event shouldn't propagate up and cause 'edge' to run. + event.stopPropagation(); + + // Add up the handle offsets. + scope_Handles.forEach(function(a){ + total += offset(a)[ options.style ]; + }); + + // Find the handle closest to the tapped position. + handleNumber = ( location < total/2 || scope_Handles.length === 1 ) ? 0 : 1; + + location -= offset(scope_Base)[ options.style ]; + + // Calculate the new position. + to = ( location * 100 ) / baseSize(); + + if ( !options.events.snap ) { + // Flag the slider as it is now in a transitional state. + // Transition takes 300 ms, so re-enable the slider afterwards. + addClassFor( scope_Target, Classes[14], 300 ); + } + + // Support 'disabled' handles + if ( scope_Handles[handleNumber].hasAttribute('disabled') ) { + return false; + } + + // Find the closest handle and calculate the tapped point. + // The set handle to the new position. + setHandle( scope_Handles[handleNumber], to ); + + fireEvent('slide', handleNumber); + fireEvent('set', handleNumber); + fireEvent('change', handleNumber); + + if ( options.events.snap ) { + start(event, { handles: [scope_Handles[total]] }); + } + } + + // Attach events to several slider parts. + function events ( behaviour ) { + + var i, drag; + + // Attach the standard drag event to the handles. + if ( !behaviour.fixed ) { + + for ( i = 0; i < scope_Handles.length; i += 1 ) { + + // These events are only bound to the visual handle + // element, not the 'real' origin element. + attach ( actions.start, scope_Handles[i].children[0], start, { + handles: [ scope_Handles[i] ] + }); + } + } + + // Attach the tap event to the slider base. + if ( behaviour.tap ) { + + attach ( actions.start, scope_Base, tap, { + handles: scope_Handles + }); + } + + // Make the range dragable. + if ( behaviour.drag ){ + + drag = [scope_Base.getElementsByClassName( Classes[7] )[0]]; + addClass(drag[0], Classes[10]); + + // When the range is fixed, the entire range can + // be dragged by the handles. The handle in the first + // origin will propagate the start event upward, + // but it needs to be bound manually on the other. + if ( behaviour.fixed ) { + drag.push(scope_Handles[(drag[0] === scope_Handles[0] ? 1 : 0)].children[0]); + } + + drag.forEach(function( element ) { + attach ( actions.start, element, start, { + handles: scope_Handles + }); + }); + } + } + + + // Test suggested values and apply margin, step. + function setHandle ( handle, to, noLimitOption ) { + + var trigger = handle !== scope_Handles[0] ? 1 : 0, + lowerMargin = scope_Locations[0] + options.margin, + upperMargin = scope_Locations[1] - options.margin, + lowerLimit = scope_Locations[0] + options.limit, + upperLimit = scope_Locations[1] - options.limit; + + // For sliders with multiple handles, + // limit movement to the other handle. + // Apply the margin option by adding it to the handle positions. + if ( scope_Handles.length > 1 ) { + to = trigger ? Math.max( to, lowerMargin ) : Math.min( to, upperMargin ); + } + + // The limit option has the opposite effect, limiting handles to a + // maximum distance from another. Limit must be > 0, as otherwise + // handles would be unmoveable. 'noLimitOption' is set to 'false' + // for the .val() method, except for pass 4/4. + if ( noLimitOption !== false && options.limit && scope_Handles.length > 1 ) { + to = trigger ? Math.min ( to, lowerLimit ) : Math.max( to, upperLimit ); + } + + // Handle the step option. + to = scope_Spectrum.getStep( to ); + + // Limit to 0/100 for .val input, trim anything beyond 7 digits, as + // JavaScript has some issues in its floating point implementation. + to = limit(parseFloat(to.toFixed(7))); + + // Return false if handle can't move. + if ( to === scope_Locations[trigger] ) { + return false; + } + + // Set the handle to the new position. + handle.style[options.style] = to + '%'; + + // Force proper handle stacking + if ( !handle.previousSibling ) { + removeClass(handle, Classes[17]); + if ( to > 50 ) { + addClass(handle, Classes[17]); + } + } + + // Update locations. + scope_Locations[trigger] = to; + + // Convert the value to the slider stepping/range. + scope_Values[trigger] = scope_Spectrum.fromStepping( to ); + + fireEvent('update', trigger); + + return true; + } + + // Loop values from value method and apply them. + function setValues ( count, values ) { + + var i, trigger, to; + + // With the limit option, we'll need another limiting pass. + if ( options.limit ) { + count += 1; + } + + // If there are multiple handles to be set run the setting + // mechanism twice for the first handle, to make sure it + // can be bounced of the second one properly. + for ( i = 0; i < count; i += 1 ) { + + trigger = i%2; + + // Get the current argument from the array. + to = values[trigger]; + + // Setting with null indicates an 'ignore'. + // Inputting 'false' is invalid. + if ( to !== null && to !== false ) { + + // If a formatted number was passed, attemt to decode it. + if ( typeof to === 'number' ) { + to = String(to); + } + + to = options.format.from( to ); + + // Request an update for all links if the value was invalid. + // Do so too if setting the handle fails. + if ( to === false || isNaN(to) || setHandle( scope_Handles[trigger], scope_Spectrum.toStepping( to ), i === (3 - options.dir) ) === false ) { + fireEvent('update', trigger); + } + } + } + } + + // Set the slider value. + function valueSet ( input ) { + + var count, values = asArray( input ), i; + + // The RTL settings is implemented by reversing the front-end, + // internal mechanisms are the same. + if ( options.dir && options.handles > 1 ) { + values.reverse(); + } + + // Animation is optional. + // Make sure the initial values where set before using animated placement. + if ( options.animate && scope_Locations[0] !== -1 ) { + addClassFor( scope_Target, Classes[14], 300 ); + } + + // Determine how often to set the handles. + count = scope_Handles.length > 1 ? 3 : 1; + + if ( values.length === 1 ) { + count = 1; + } + + setValues ( count, values ); + + // Fire the 'set' event for both handles. + for ( i = 0; i < scope_Handles.length; i++ ) { + fireEvent('set', i); + } + } + + // Get the slider value. + function valueGet ( ) { + + var i, retour = []; + + // Get the value from all handles. + for ( i = 0; i < options.handles; i += 1 ){ + retour[i] = options.format.to( scope_Values[i] ); + } + + return inSliderOrder( retour ); + } + + // Removes classes from the root and empties it. + function destroy ( ) { + Classes.forEach(function(cls){ + if ( !cls ) { return; } // Ignore empty classes + removeClass(scope_Target, cls); + }); + scope_Target.innerHTML = ''; + delete scope_Target.noUiSlider; + } + + // Get the current step size for the slider. + function getCurrentStep ( ) { + + // Check all locations, map them to their stepping point. + // Get the step point, then find it in the input list. + var retour = scope_Locations.map(function( location, index ){ + + var step = scope_Spectrum.getApplicableStep( location ), + + // As per #391, the comparison for the decrement step can have some rounding issues. + // Round the value to the precision used in the step. + stepDecimals = countDecimals(String(step[2])), + + // Get the current numeric value + value = scope_Values[index], + + // To move the slider 'one step up', the current step value needs to be added. + // Use null if we are at the maximum slider value. + increment = location === 100 ? null : step[2], + + // Going 'one step down' might put the slider in a different sub-range, so we + // need to switch between the current or the previous step. + prev = Number((value - step[2]).toFixed(stepDecimals)), + + // If the value fits the step, return the current step value. Otherwise, use the + // previous step. Return null if the slider is at its minimum value. + decrement = location === 0 ? null : (prev >= step[1]) ? step[2] : (step[0] || false); + + return [decrement, increment]; + }); + + // Return values in the proper order. + return inSliderOrder( retour ); + } + + // Attach an event to this slider, possibly including a namespace + function bindEvent ( namespacedEvent, callback ) { + scope_Events[namespacedEvent] = scope_Events[namespacedEvent] || []; + scope_Events[namespacedEvent].push(callback); + + // If the event bound is 'update,' fire it immediately for all handles. + if ( namespacedEvent.split('.')[0] === 'update' ) { + scope_Handles.forEach(function(a, index){ + fireEvent('update', index); + }); + } + } + + // Undo attachment of event + function removeEvent ( namespacedEvent ) { + + var event = namespacedEvent.split('.')[0], + namespace = namespacedEvent.substring(event.length); + + Object.keys(scope_Events).forEach(function( bind ){ + + var tEvent = bind.split('.')[0], + tNamespace = bind.substring(tEvent.length); + + if ( (!event || event === tEvent) && (!namespace || namespace === tNamespace) ) { + delete scope_Events[bind]; + } + }); + } + + + // Throw an error if the slider was already initialized. + if ( scope_Target.noUiSlider ) { + throw new Error('Slider was already initialized.'); + } + + + // Create the base element, initialise HTML and set classes. + // Add handles and links. + scope_Base = addSlider( options.dir, options.ort, scope_Target ); + scope_Handles = addHandles( options.handles, options.dir, scope_Base ); + + // Set the connect classes. + addConnection ( options.connect, scope_Target, scope_Handles ); + + // Attach user events. + events( options.events ); + + if ( options.pips ) { + pips(options.pips); + } + + return { + destroy: destroy, + steps: getCurrentStep, + on: bindEvent, + off: removeEvent, + get: valueGet, + set: valueSet + }; + +} + + + // Run the standard initializer + function initialize ( target, originalOptions ) { + + if ( !target.nodeName ) { + throw new Error('noUiSlider.create requires a single element.'); + } + + // Test the options and create the slider environment; + var options = testOptions( originalOptions, target ), + slider = closure( target, options ); + + // Use the public value method to set the start values. + slider.set(options.start); + + target.noUiSlider = slider; + } + + // Use an object instead of a function for future expansibility; + return { + create: initialize + }; + +})); \ No newline at end of file diff --git a/content/src/view.js b/content/src/view.js index 5e469fd3..ea94ea3e 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -5,6 +5,7 @@ var $ = require('jquery'), jqueryui = require('jquery-ui'), jqueryuisliderpips = require('jquery-ui-slider-pips'), + nouislider = require('nouislider'), filetype = require('filetype'), tooltipster = require('tooltipster'), see = require('see'), diff --git a/package.json b/package.json index b8143781..948c20e9 100644 --- a/package.json +++ b/package.json @@ -67,9 +67,11 @@ "html2canvas": "./content/lib/html2canvas.js", "iced-coffee-script": "./content/lib/iced-coffee-script.js", "jquery": "./content/lib/jquery.js", + "jquery-turtle": "./content/lib/jquery-turtle.js", "jquery-ui": "./content/lib/jquery-ui.js", "jquery-ui-slider-pips": "./content/lib/jquery-ui-slider-pips.js", "html2canvas" : "./content/lib/html2canvas.js", + "nouislider" : "./content/lib/nouislider.js", "palette": "./content/src/palette.js", "pencil-tracer": "./content/lib/pencil-tracer.js", "see": "./content/lib/see.js", @@ -97,6 +99,11 @@ "jquery:jQuery" ] }, + "jquery-turtle": { + "depends": [ + "jquery:jQuery" + ] + }, "see": { "exports": "see", "depends": [ From 73638439aba45a57ac447ba338ec895f53500b05 Mon Sep 17 00:00:00 2001 From: Jeremy Ruten Date: Thu, 23 Jul 2015 23:04:41 -0600 Subject: [PATCH 106/199] Update pencil-tracer.js, ignore 'after' and 'leave' events --- content/lib/pencil-tracer.js | 13956 ++++++++++++++++++++++++--------- content/src/debug.js | 33 +- 2 files changed, 10197 insertions(+), 3792 deletions(-) diff --git a/content/lib/pencil-tracer.js b/content/lib/pencil-tracer.js index 301d98ac..6c25d5c8 100644 --- a/content/lib/pencil-tracer.js +++ b/content/lib/pencil-tracer.js @@ -1,20 +1,23 @@ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pencilTracer = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o").expressions[0].constructor, 'Param': this.coffee.nodes("(a)->").expressions[0].params[0].constructor, - 'Splat': this.coffee.nodes("[a...]").expressions[0].base.objects[0].constructor, - 'Expansion': this.coffee.nodes("[...]").expressions[0].base.objects[0].constructor, 'While': this.coffee.nodes("0 while true").expressions[0].constructor, 'Op': this.coffee.nodes("1+1").expressions[0].constructor, - 'In': this.coffee.nodes("0 in []").expressions[0].constructor, 'Try': this.coffee.nodes("try").expressions[0].constructor, 'Throw': this.coffee.nodes("throw 0").expressions[0].constructor, - 'Existence': this.coffee.nodes("a?").expressions[0].constructor, 'Parens': this.coffee.nodes("(0)").expressions[0].base.constructor, 'For': this.coffee.nodes("0 for a in []").expressions[0].constructor, 'Switch': this.coffee.nodes("switch a\n when 0 then 0").expressions[0].constructor, @@ -68,41 +58,296 @@ } }; - CoffeeScriptInstrumenter.prototype.createInstrumentedNode = function(targetNode, eventType) { - var eventObj, instrumentedNode, locationData, locationObj, varsObj; - if (targetNode instanceof this.nodeTypes.IcedTailCall) { - targetNode = targetNode.value; + CoffeeScriptInstrumenter.prototype.temporaryVariable = function(base) { + var curName, index, name; + name = "_penciltracer_" + base; + index = 0; + while (true) { + curName = name + index; + if (indexOf.call(this.referencedVars, curName) < 0) { + this.referencedVars.push(curName); + return curName; + } + index++; + } + }; + + CoffeeScriptInstrumenter.prototype.lastNonComment = function(list) { + var i; + i = list.length; + while (i--) { + if (!(list[i] instanceof this.nodeTypes.Comment)) { + return list[i]; + } + } + return null; + }; + + CoffeeScriptInstrumenter.prototype.createInstrumentedNode = function(eventType, options) { + var eventObj, extra, f, functionCalls, instrumentedNode, location, locationObj, name, ref, ref1, ref2, soakify, vars; + if (options == null) { + options = {}; + } + if (options.node instanceof this.nodeTypes.IcedTailCall) { + options.node = options.node.value; + } + location = (ref = options.location) != null ? ref : options.node.locationData; + if (eventType !== "leave") { + vars = (ref1 = options.vars) != null ? ref1 : (eventType === "enter" ? this.findArguments(options.node) : this.findVariables(options.node)); + } + if (eventType === "after") { + functionCalls = (ref2 = options.functionCalls) != null ? ref2 : this.findFunctionCalls(options.node); + } + locationObj = "{ first_line: " + (location.first_line + 1) + ","; + locationObj += " first_column: " + (location.first_column + 1) + ","; + locationObj += " last_line: " + (location.last_line + 1) + ","; + locationObj += " last_column: " + (location.last_column + 1) + " }"; + soakify = function(name) { + if (name.indexOf(".") === -1) { + return "(if typeof " + name + " is 'undefined' then undefined else " + name + ")"; + } else { + return name.replace(/\./g, "?."); + } + }; + extra = (function() { + switch (eventType) { + case "before": + case "after": + return "vars: [" + ((function() { + var j, len, results; + results = []; + for (j = 0, len = vars.length; j < len; j++) { + name = vars[j]; + results.push("{name: '" + name + "', value: " + (soakify(name)) + "}"); + } + return results; + })()) + "]"; + case "enter": + return "vars: [" + ((function() { + var j, len, results; + results = []; + for (j = 0, len = vars.length; j < len; j++) { + name = vars[j]; + results.push("{name: '" + name + "', value: " + name + "}"); + } + return results; + })()) + "]"; + case "leave": + return "returnOrThrow: " + options.returnOrThrowVar; + } + })(); + if (eventType === "after") { + extra += ", functionCalls: [" + ((function() { + var j, len, results; + results = []; + for (j = 0, len = functionCalls.length; j < len; j++) { + f = functionCalls[j]; + results.push("{name: '" + f.name + "', value: " + f.tempVar + "}"); + } + return results; + })()) + "]"; } - locationData = targetNode.locationData; - locationObj = "{ first_line: " + (locationData.first_line + 1) + ","; - locationObj += " first_column: " + (locationData.first_column + 1) + ","; - locationObj += " last_line: " + (locationData.last_line + 1) + ","; - locationObj += " last_column: " + (locationData.last_column + 1) + " }"; - eventObj = this.options.trackVariables ? (varsObj = targetNode.pencilTracerScope.toCode(this.findVariables(targetNode)), "{ location: " + locationObj + ", type: '" + eventType + "', vars: " + varsObj + " }") : "{ location: " + locationObj + ", type: '" + eventType + "' }"; + eventObj = "{ location: " + locationObj + ", type: '" + eventType + "', " + extra + " }"; instrumentedNode = this.coffee.nodes(this.options.traceFunc + "(" + eventObj + ")").expressions[0]; instrumentedNode.pencilTracerInstrumented = true; return instrumentedNode; }; - CoffeeScriptInstrumenter.prototype.createInstrumentedExpr = function(targetNode, eventType, originalExpr) { - var parensBlock; + CoffeeScriptInstrumenter.prototype.createInstrumentedExpr = function(originalExpr) { + var parensBlock, tempVar; + tempVar = this.temporaryVariable("temp"); parensBlock = this.coffee.nodes("(0)").expressions[0]; parensBlock.base.body.expressions = []; - parensBlock.base.body.expressions[0] = this.createInstrumentedNode(targetNode, "code"); - parensBlock.base.body.expressions[1] = originalExpr; + parensBlock.base.body.expressions[0] = this.createInstrumentedNode("before", { + node: originalExpr + }); + parensBlock.base.body.expressions[1] = this.createAssignNode(tempVar, originalExpr); + parensBlock.base.body.expressions[2] = this.createInstrumentedNode("after", { + node: originalExpr + }); + parensBlock.base.body.expressions[3] = this.coffee.nodes(tempVar).expressions[0]; return parensBlock; }; + CoffeeScriptInstrumenter.prototype.createAssignNode = function(varName, valueNode) { + var assignNode; + assignNode = this.coffee.nodes(varName + " = 0").expressions[0]; + assignNode.value = valueNode; + return assignNode; + }; + + CoffeeScriptInstrumenter.prototype.findVariables = function(node, parent, vars) { + var j, lastProp, len, name, prop, ref, skip; + if (parent == null) { + parent = null; + } + if (vars == null) { + vars = []; + } + if (node instanceof this.nodeTypes.Value && node.base instanceof this.nodeTypes.Literal && node.base.isAssignable()) { + skip = parent instanceof this.nodeTypes.Assign && parent.context === "object" && parent.variable === node; + skip || (skip = parent instanceof this.nodeTypes.Call && parent.variable === node && node.properties.length === 0); + if (!skip) { + name = node["this"] ? "@" : node.base.value + "."; + lastProp = node.properties[node.properties.length - 1]; + ref = node.properties; + for (j = 0, len = ref.length; j < len; j++) { + prop = ref[j]; + if (!(prop instanceof this.nodeTypes.Access) || prop.soak || (prop === lastProp && parent instanceof this.nodeTypes.Call && parent.variable === node)) { + break; + } + name += prop.name.value + "."; + } + if (name !== "@") { + name = name.slice(0, -1); + } + if (vars.indexOf(name) === -1) { + vars.push(name); + } + } + } + node.eachChild((function(_this) { + return function(child) { + skip = child instanceof _this.nodeTypes.Block && !(node instanceof _this.nodeTypes.Parens); + skip || (skip = child instanceof _this.nodeTypes.Code); + skip || (skip = !_this.shouldInstrumentNode(child)); + skip || (skip = node instanceof _this.nodeTypes.Defer); + if (!skip) { + return _this.findVariables(child, node, vars); + } + }; + })(this)); + return vars; + }; + + CoffeeScriptInstrumenter.prototype.findArguments = function(codeNode) { + var args, j, len, name, paramNode, ref; + if (!(codeNode instanceof this.nodeTypes.Code)) { + throw new Error("findArguments() expects a Code node"); + } + args = []; + ref = codeNode.params; + for (j = 0, len = ref.length; j < len; j++) { + paramNode = ref[j]; + if (paramNode instanceof this.nodeTypes.Param) { + name = paramNode.name; + if (name instanceof this.nodeTypes.Literal) { + args.push(name.value); + } else if (name instanceof this.nodeTypes.Value) { + args.push("@" + name.properties[0].name.value); + } else { + args.push.apply(args, this.findVariables(name)); + } + } + } + return args; + }; + + CoffeeScriptInstrumenter.prototype.findFunctionCalls = function(node, parent, grandparent, vars) { + var j, lastProp, len, name, prop, ref, soak; + if (parent == null) { + parent = null; + } + if (grandparent == null) { + grandparent = null; + } + if (vars == null) { + vars = []; + } + if (node instanceof this.nodeTypes.Call && !(grandparent instanceof this.nodeTypes.Op && grandparent.operator === "new")) { + soak = node.soak; + if (node.variable instanceof this.nodeTypes.Value) { + ref = node.variable.properties; + for (j = 0, len = ref.length; j < len; j++) { + prop = ref[j]; + soak || (soak = prop.soak); + } + } + if (!soak) { + name = ""; + if (node.isSuper) { + name = "super"; + } else if (node.variable instanceof this.nodeTypes.Value) { + if (node.variable.properties.length > 0) { + lastProp = node.variable.properties[node.variable.properties.length - 1]; + if (lastProp instanceof this.nodeTypes.Access) { + name = lastProp.name.value; + } + } else if (node.variable.base instanceof this.nodeTypes.Literal) { + name = node.variable.base.value; + } + } + node.pencilTracerReturnVar = this.temporaryVariable("returnVar"); + vars.push({ + name: name, + tempVar: node.pencilTracerReturnVar + }); + } + } + node.eachChild((function(_this) { + return function(child) { + var skip; + skip = child instanceof _this.nodeTypes.Block && !(node instanceof _this.nodeTypes.Parens); + skip || (skip = child instanceof _this.nodeTypes.Code); + skip || (skip = !_this.shouldInstrumentNode(child)); + if (!skip) { + return _this.findFunctionCalls(child, node, parent, vars); + } + }; + })(this)); + return vars; + }; + + CoffeeScriptInstrumenter.prototype.nodeIsObj = function(node) { + return node instanceof this.nodeTypes.Value && node.isObject(true); + }; + + CoffeeScriptInstrumenter.prototype.nodeIsClassProperty = function(node, className) { + return this.nodeIsObj(node) || (node instanceof this.nodeTypes.Assign && node.variable.looksStatic(className)) || (node instanceof this.nodeTypes.Assign && node.variable["this"]); + }; + CoffeeScriptInstrumenter.prototype.shouldSkipNode = function(node) { return node.pencilTracerInstrumented || node instanceof this.nodeTypes.IcedRuntime; }; CoffeeScriptInstrumenter.prototype.shouldInstrumentNode = function(node) { - return !node.pencilTracerInstrumented && !(node instanceof this.nodeTypes.IcedRuntime) && (!(node instanceof this.nodeTypes.IcedTailCall) || node.value) && !(node instanceof this.nodeTypes.Comment) && !(node instanceof this.nodeTypes.While) && !(node instanceof this.nodeTypes.Switch) && !(node instanceof this.nodeTypes.If); + return !node.pencilTracerInstrumented && !(node instanceof this.nodeTypes.IcedRuntime) && (!(node instanceof this.nodeTypes.IcedTailCall) || node.value) && !(node instanceof this.nodeTypes.Comment) && !(node instanceof this.nodeTypes.For) && !(node instanceof this.nodeTypes.While) && !(node instanceof this.nodeTypes.Switch) && !(node instanceof this.nodeTypes.If) && !(node instanceof this.nodeTypes.Class) && !(node instanceof this.nodeTypes.Try) && !(node instanceof this.nodeTypes.Await); + }; + + CoffeeScriptInstrumenter.prototype.mapChildrenArray = function(children, func) { + var child, index, j, len, results; + results = []; + for (index = j = 0, len = children.length; j < len; index = ++j) { + child = children[index]; + if (isArray(child)) { + results.push(this.mapChildrenArray(child, func)); + } else { + results.push(children[index] = func(child)); + } + } + return results; + }; + + CoffeeScriptInstrumenter.prototype.mapChildren = function(node, func) { + var attr, childrenAttrs, j, len, results; + childrenAttrs = node.children.slice(); + childrenAttrs.push("icedContinuationBlock"); + results = []; + for (j = 0, len = childrenAttrs.length; j < len; j++) { + attr = childrenAttrs[j]; + if (node[attr]) { + if (isArray(node[attr])) { + results.push(this.mapChildrenArray(node[attr], func)); + } else { + results.push(node[attr] = func(node[attr])); + } + } + } + return results; }; CoffeeScriptInstrumenter.prototype.compileAst = function(ast, originalCode, compileOptions) { - var SourceMap, answer, compilerName, currentColumn, currentLine, fragment, fragments, header, i, js, len, map, newLines; + var SourceMap, answer, compilerName, currentColumn, currentLine, fragment, fragments, header, j, js, len, map, newLines; SourceMap = this.coffee.compile("", { sourceMap: true }).sourceMap.constructor; @@ -119,8 +364,8 @@ } currentColumn = 0; js = ""; - for (i = 0, len = fragments.length; i < len; i++) { - fragment = fragments[i]; + for (j = 0, len = fragments.length; j < len; j++) { + fragment = fragments[j]; if (compileOptions.sourceMap) { if (fragment.locationData && !/^[;\s]*$/.test(fragment.code)) { map.add([fragment.locationData.first_line, fragment.locationData.first_column], [currentLine, currentColumn], { @@ -154,161 +399,229 @@ } }; - CoffeeScriptInstrumenter.prototype.findVariables = function(node, parent, vars) { - var skip; - if (parent == null) { - parent = null; - } - if (vars == null) { - vars = []; - } - if (node instanceof this.nodeTypes.Value && node.base instanceof this.nodeTypes.Literal && node.base.isAssignable()) { - skip = parent instanceof this.nodeTypes.Assign && parent.context === "object" && parent.variable === node; - if (!skip) { - if (vars.indexOf(node.base.value) === -1) { - vars.push(node.base.value); - } - } - } - node.eachChild((function(_this) { - return function(child) { - return _this.findVariables(child, node, vars); - }; - })(this)); - return vars; - }; - - CoffeeScriptInstrumenter.prototype.findArguments = function(paramNode) { - var name; - if (!(paramNode instanceof this.nodeTypes.Param)) { - throw new Error("findArguments() expects a Param node"); - } - name = paramNode.name; - if (name instanceof this.nodeTypes.Literal) { - return [name.value]; - } else if (name instanceof this.nodeTypes.Value) { - return []; - } else { - return this.findVariables(name); - } - }; - - CoffeeScriptInstrumenter.prototype.findScopes = function(node, parent, scopes, depth) { - var arg, i, j, len, len1, param, ref, ref1; + CoffeeScriptInstrumenter.prototype.instrumentTree = function(node, parent, inClass, returnOrThrowVar) { + var after, afterNode, before, beforeNode, block, caseClause, childIndex, children, expression, getVars, i, j, k, lastChild, len, len1, location, objValue, parensBlock, prop, recursed, ref, ref1, ref2, returnValue, temp, thrownValue, tryNode, vars; if (parent == null) { parent = null; } - if (scopes == null) { - scopes = []; - } - if (depth == null) { - depth = 0; - } - if (node instanceof this.nodeTypes.Block) { - depth += 1; - scopes[depth] = new Scope(scopes[depth - 1]); - if (parent instanceof this.nodeTypes.Code) { - ref = parent.params; - for (i = 0, len = ref.length; i < len; i++) { - param = ref[i]; - ref1 = this.findArguments(param); - for (j = 0, len1 = ref1.length; j < len1; j++) { - arg = ref1[j]; - scopes[depth].add(arg, "argument"); - } - } - } - } - node.pencilTracerScope = scopes[depth]; - if (node instanceof this.nodeTypes.Assign && node.context !== "object") { - if (node.variable.base instanceof this.nodeTypes.Literal) { - scopes[depth].add(node.variable.base.value, "variable"); - } - } - node.eachChild((function(_this) { - return function(child) { - return _this.findScopes(child, node, scopes, depth); - }; - })(this)); - if (node.icedContinuationBlock != null) { - return this.findScopes(node.icedContinuationBlock, node, scopes, depth); - } - }; - - CoffeeScriptInstrumenter.prototype.instrumentTree = function(node, parent) { - var caseClause, childIndex, children, expression, i, instrumentedNode, len, ref, tryBlock, tryNode; - if (parent == null) { - parent = null; + if (inClass == null) { + inClass = false; } if (this.shouldSkipNode(node)) { return; } - if (node instanceof this.nodeTypes.Block && !(parent instanceof this.nodeTypes.Parens) && !(parent instanceof this.nodeTypes.Class)) { + if (node instanceof this.nodeTypes.Class) { + inClass = node; + } + if (this.nodeIsObj(node)) { + inClass = false; + } + recursed = false; + if (node instanceof this.nodeTypes.Block && !(parent instanceof this.nodeTypes.Parens)) { children = node.expressions; + lastChild = this.lastNonComment(children); childIndex = 0; + if (!returnOrThrowVar) { + returnOrThrowVar = this.temporaryVariable("returnOrThrow"); + children.unshift(this.coffee.nodes(returnOrThrowVar + " = {}").expressions[0]); + childIndex = 1; + } while (childIndex < children.length) { expression = children[childIndex]; + if (inClass && this.nodeIsObj(expression) && expression.base.properties.length > 1) { + children.splice(childIndex, 1); + ref = expression.base.properties; + for (i = j = 0, len = ref.length; j < len; i = ++j) { + prop = ref[i]; + objValue = this.coffee.nodes("{}").expressions[0]; + objValue.locationData = objValue.base.locationData = prop.locationData; + objValue.base.properties = objValue.base.objects = [prop]; + objValue.base.generated = expression.base.generated; + children.splice(childIndex + i, 0, objValue); + } + expression = children[childIndex]; + } if (this.shouldInstrumentNode(expression)) { - instrumentedNode = this.createInstrumentedNode(expression, "code"); - children.splice(childIndex, 0, instrumentedNode); + beforeNode = this.createInstrumentedNode("before", { + node: expression + }); + afterNode = this.createInstrumentedNode("after", { + node: expression + }); + children.splice(childIndex, 0, beforeNode); + childIndex++; + children.splice(childIndex + 1, 0, afterNode); childIndex++; + if (expression.pencilTracerReturnVar) { + children[childIndex - 1] = this.createAssignNode(expression.pencilTracerReturnVar, expression); + } + if (expression instanceof this.nodeTypes.Return) { + returnValue = expression.expression || this.coffee.nodes("undefined").expressions[0]; + if (returnValue.pencilTracerReturnVar) { + returnValue = this.createAssignNode(returnValue.pencilTracerReturnVar, returnValue); + } + children[childIndex - 1] = this.createAssignNode(returnOrThrowVar + ".value", returnValue); + children.splice(childIndex + 1, 0, this.coffee.nodes("return " + returnOrThrowVar + ".value").expressions[0]); + childIndex++; + } else if (expression instanceof this.nodeTypes.Throw) { + thrownValue = expression.expression; + if (thrownValue.pencilTracerReturnVar) { + thrownValue = this.createAssignNode(thrownValue.pencilTracerReturnVar, thrownValue); + } + children[childIndex - 1] = this.createAssignNode(returnOrThrowVar + ".value", thrownValue); + children.splice(childIndex + 1, 0, this.coffee.nodes("throw " + returnOrThrowVar + ".value").expressions[0]); + childIndex++; + } else if (expression instanceof this.nodeTypes.Literal && ((ref1 = expression.value) === "break" || ref1 === "continue")) { + temp = children[childIndex]; + children[childIndex] = children[childIndex - 1]; + children[childIndex - 1] = temp; + } else if (expression === lastChild && !expression.jumps() && !(expression instanceof this.nodeTypes.Await) && !(inClass && this.nodeIsClassProperty(expression, inClass.determineName())) && !(parent instanceof this.nodeTypes.Try && parent.ensure === node)) { + children[childIndex - 1] = this.createAssignNode(returnOrThrowVar + ".value", children[childIndex - 1]); + children.splice(childIndex + 1, 0, this.coffee.nodes(returnOrThrowVar + ".value").expressions[0]); + children[childIndex + 1].icedHasAutocbFlag = expression.icedHasAutocbFlag; + childIndex++; + } } - this.instrumentTree(expression, node); + this.instrumentTree(expression, node, inClass, returnOrThrowVar); childIndex++; } - if (parent instanceof this.nodeTypes.For) { - instrumentedNode = this.createInstrumentedNode(parent, "code"); - return children.unshift(instrumentedNode); + recursed = true; + } else if (node instanceof this.nodeTypes.For) { + if (!node.range) { + node.source = this.createInstrumentedExpr(node.source); } - } else if (node instanceof this.nodeTypes.While) { - node.condition = this.createInstrumentedExpr(node, "code", node.condition); - return node.eachChild((function(_this) { - return function(child) { - return _this.instrumentTree(child, node); + if (node.guard) { + node.guard = this.createInstrumentedExpr(node.guard); + } + if (node.step) { + node.step = this.createInstrumentedExpr(node.step); + } + getVars = (function(_this) { + return function(n) { + if (n instanceof _this.nodeTypes.Literal) { + return [n.value]; + } else { + return _this.findVariables(n); + } }; - })(this)); + })(this); + if (node.name && node.index) { + if (node.object) { + location = { + first_line: node.name.locationData.first_line, + first_column: node.name.locationData.first_column, + last_line: node.index.locationData.last_line, + last_column: node.index.locationData.last_column + }; + } else { + location = { + first_line: node.index.locationData.first_line, + first_column: node.index.locationData.first_column, + last_line: node.name.locationData.last_line, + last_column: node.name.locationData.last_column + }; + } + vars = getVars(node.name).concat(getVars(node.index)); + } else if (node.name) { + location = node.name.locationData; + vars = getVars(node.name); + } else if (node.index) { + location = node.index.locationData; + vars = getVars(node.index); + } else { + location = node.locationData; + vars = []; + } + before = this.createInstrumentedNode("before", { + location: location, + vars: vars + }); + after = this.createInstrumentedNode("after", { + location: location, + vars: vars, + functionCalls: [] + }); + if (node.guard) { + parensBlock = this.coffee.nodes("(0)").expressions[0]; + parensBlock.base.body.expressions = [before, after, node.guard]; + node.guard = parensBlock; + } else { + node.body.expressions.unshift(before, after); + } + } else if (node instanceof this.nodeTypes.While) { + node.condition = this.createInstrumentedExpr(node.condition); + if (node.guard) { + node.guard = this.createInstrumentedExpr(node.guard); + } } else if (node instanceof this.nodeTypes.Switch) { if (node.subject) { - node.subject = this.createInstrumentedExpr(node, "code", node.subject); + node.subject = this.createInstrumentedExpr(node.subject); } - ref = node.cases; - for (i = 0, len = ref.length; i < len; i++) { - caseClause = ref[i]; - if (caseClause[0] instanceof Array) { - caseClause[0][0] = this.createInstrumentedExpr(caseClause[0][0], "code", caseClause[0][0]); + ref2 = node.cases; + for (k = 0, len1 = ref2.length; k < len1; k++) { + caseClause = ref2[k]; + if (isArray(caseClause[0])) { + caseClause[0][0] = this.createInstrumentedExpr(caseClause[0][0]); } else { - caseClause[0] = this.createInstrumentedExpr(caseClause[0], "code", caseClause[0]); + caseClause[0] = this.createInstrumentedExpr(caseClause[0]); } } - return node.eachChild((function(_this) { - return function(child) { - return _this.instrumentTree(child, node); - }; - })(this)); } else if (node instanceof this.nodeTypes.If) { - node.condition = this.createInstrumentedExpr(node.condition, "code", node.condition); - return node.eachChild((function(_this) { - return function(child) { - return _this.instrumentTree(child, node); - }; - })(this)); + node.condition = this.createInstrumentedExpr(node.condition); + } else if (node instanceof this.nodeTypes.Class) { + before = this.createInstrumentedNode("before", { + node: node + }); + after = this.createInstrumentedNode("after", { + node: node + }); + node.body.expressions.unshift(before, after); + } else if (node instanceof this.nodeTypes.Try) { + if (node.recovery && node.errorVariable) { + if (node.errorVariable instanceof this.nodeTypes.Literal) { + vars = [node.errorVariable.value]; + } else { + vars = this.findVariables(node.errorVariable); + } + before = this.createInstrumentedNode("before", { + node: node.errorVariable, + vars: vars + }); + after = this.createInstrumentedNode("after", { + node: node.errorVariable, + vars: vars, + functionCalls: [] + }); + node.recovery.expressions.unshift(before, after); + } } else if (node instanceof this.nodeTypes.Code) { - tryBlock = this.coffee.nodes("try\nfinally"); - tryNode = tryBlock.expressions[0]; + returnOrThrowVar = this.temporaryVariable("returnOrThrow"); + block = this.coffee.nodes(returnOrThrowVar + " = { type: 'return', value: undefined }\ntry\ncatch " + this.caughtErrorVar + "\n " + returnOrThrowVar + ".type = 'throw'\n " + returnOrThrowVar + ".value = " + this.caughtErrorVar + "\n throw " + this.caughtErrorVar + "\nfinally"); + tryNode = block.expressions[1]; tryNode.attempt = node.body; - tryBlock.expressions.unshift(this.createInstrumentedNode(node, "enter")); - tryNode.ensure.expressions.unshift(this.createInstrumentedNode(node, "leave")); - node.body = tryBlock; - return this.instrumentTree(tryNode.attempt, tryNode); - } else { - node.eachChild((function(_this) { + block.expressions.unshift(this.createInstrumentedNode("enter", { + node: node + })); + tryNode.ensure.expressions.unshift(this.createInstrumentedNode("leave", { + node: node, + returnOrThrowVar: returnOrThrowVar + })); + node.body = block; + this.instrumentTree(tryNode.attempt, tryNode, inClass, returnOrThrowVar); + recursed = true; + } + if (!recursed) { + return this.mapChildren(node, (function(_this) { return function(child) { - return _this.instrumentTree(child, node); + var ret; + ret = child; + if (child.pencilTracerReturnVar) { + ret = _this.createAssignNode(child.pencilTracerReturnVar, child); + } + _this.instrumentTree(child, node, inClass, returnOrThrowVar); + return ret; }; })(this)); - if (node.icedContinuationBlock != null) { - return this.instrumentTree(node.icedContinuationBlock, node); - } } }; @@ -321,22 +634,20 @@ sourceMap: this.options.sourceMap, literate: this.options.literate }; - csOptions.referencedVars = (function() { - var i, len, ref, results; + this.referencedVars = csOptions.referencedVars = (function() { + var j, len, ref, results; ref = this.coffee.tokens(code, csOptions); results = []; - for (i = 0, len = ref.length; i < len; i++) { - token = ref[i]; + for (j = 0, len = ref.length; j < len; j++) { + token = ref[j]; if (token.variable) { results.push(token[1]); } } return results; }).call(this); + this.caughtErrorVar = this.temporaryVariable("err"); ast = this.coffee.nodes(code, csOptions); - if (this.options.trackVariables) { - this.findScopes(ast); - } this.instrumentTree(ast); if (this.options.ast) { return ast; @@ -360,7 +671,7 @@ }).call(this); -},{"./scope":4}],2:[function(require,module,exports){ +},{}],2:[function(require,module,exports){ // Generated by CoffeeScript 1.9.3 (function() { var instrumentCoffee, instrumentJs; @@ -378,4289 +689,10376 @@ },{"./coffeescript_instrumenter":1,"./javascript_instrumenter":3}],3:[function(require,module,exports){ // Generated by CoffeeScript 1.9.3 (function() { - var JavaScriptInstrumenter, STATEMENTS, STATEMENTS_WITH_BODIES, falafel, + var JavaScriptInstrumenter, acorn, escodegen, isArray, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - falafel = require("falafel"); + acorn = require("acorn"); - STATEMENTS = ["EmptyStatement", "BlockStatement", "ExpressionStatement", "IfStatement", "LabeledStatement", "BreakStatement", "ContinueStatement", "WithStatement", "SwitchStatement", "ReturnStatement", "ThrowStatement", "TryStatement", "WhileStatement", "DoWhileStatement", "ForStatement", "ForInStatement", "DebuggerStatement", "FunctionDeclaration", "VariableDeclaration"]; + escodegen = require("escodegen"); - STATEMENTS_WITH_BODIES = ["IfStatement", "LabeledStatement", "WithStatement", "WhileStatement", "DoWhileStatement", "ForStatement", "ForInStatement"]; + isArray = Array.isArray || function(value) { + return {}.toString.call(value) === '[object Array]'; + }; JavaScriptInstrumenter = (function() { - function JavaScriptInstrumenter() {} - - JavaScriptInstrumenter.prototype.traceCall = function(traceFunc, location, eventType) { - var locationObj; - locationObj = "{ first_line: " + location.start.line + ","; - locationObj += " first_column: " + (location.start.column + 1) + ","; - locationObj += " last_line: " + location.end.line + ","; - locationObj += " last_column: " + (location.end.column + 1) + " }"; - return traceFunc + "({ location: " + locationObj + ", type: '" + eventType + "' })"; - }; + function JavaScriptInstrumenter(options1) { + var base1; + this.options = options1; + if ((base1 = this.options).traceFunc == null) { + base1.traceFunc = "pencilTrace"; + } + } - JavaScriptInstrumenter.prototype.needsBraces = function(node) { - var ref, ref1; - return (ref = node.type, indexOf.call(STATEMENTS, ref) >= 0) && node.type !== "BlockStatement" && (ref1 = node.parent.type, indexOf.call(STATEMENTS_WITH_BODIES, ref1) >= 0) && !(node.parent.type === "ForStatement" && node.parent.init === node) && !(node.parent.type === "ForInStatement" && node.parent.left === node); + JavaScriptInstrumenter.prototype.temporaryVariable = function(base, needsDeclaration) { + var curName, index, name; + if (needsDeclaration == null) { + needsDeclaration = false; + } + name = "_penciltracer_" + base; + index = 0; + while (true) { + curName = name + index; + if (indexOf.call(this.referencedVars, curName) < 0) { + this.referencedVars.push(curName); + if (needsDeclaration) { + this.undeclaredVars.push(curName); + } + return curName; + } + index++; + } }; - JavaScriptInstrumenter.prototype.instrument = function(filename, code, options) { - var ref, result, traceFunc; + JavaScriptInstrumenter.prototype.createInstrumentedNode = function(eventType, options) { + var eventObj, extra, f, functionCalls, instrumentedNode, loc, locationObj, name, ref, ref1, ref2, soakify, vars; if (options == null) { options = {}; } - traceFunc = (ref = options.traceFunc) != null ? ref : "pencilTrace"; - result = falafel(code, { - locations: true - }, (function(_this) { - return function(node) { - var enter, leave, ref1, ref2, ref3, ref4, ref5, ref6; - switch (node.type) { - case "EmptyStatement": - case "ExpressionStatement": - case "BreakStatement": - case "ContinueStatement": - case "ReturnStatement": - case "ThrowStatement": - case "DebuggerStatement": - case "FunctionDeclaration": - code = _this.traceCall(traceFunc, node.loc, "code"); - node.update(code + "; " + (node.source())); - if ((ref1 = node.parent.type) === "DoWhileStatement" || ref1 === "ForInStatement") { - code = _this.traceCall(traceFunc, node.parent.loc, "code"); - node.update(code + "; " + (node.source())); - } - break; - case "VariableDeclaration": - if ((ref2 = node.parent.type) !== "ForStatement" && ref2 !== "ForInStatement") { - code = _this.traceCall(traceFunc, node.loc, "code"); - node.update(code + "; " + (node.source())); - } - break; - case "ForStatement": - code = _this.traceCall(traceFunc, ((ref3 = node.init) != null ? ref3.loc : void 0) || node.loc, "code"); - node.update(code + "; " + (node.source())); - break; - case "BlockStatement": - if ((ref4 = node.parent.type) === "FunctionDeclaration" || ref4 === "FunctionExpression") { - enter = _this.traceCall(traceFunc, node.loc, "enter"); - leave = _this.traceCall(traceFunc, node.loc, "leave"); - node.update("{ " + enter + "; try " + (node.source()) + " finally { " + leave + "; } }"); - } - if (node.parent.type === "TryStatement") { - if (node.parent.block === node) { - code = _this.traceCall(traceFunc, node.parent.loc, "code"); - node.update("{ " + code + "; " + (node.source()) + " }"); - } else if (node.parent.finalizer === node) { - code = _this.traceCall(traceFunc, node.loc, "code"); - node.update("{ " + code + "; " + (node.source()) + " }"); - } - } - if (node.parent.type === "CatchClause") { - code = _this.traceCall(traceFunc, node.parent.loc, "code"); - node.update("{ " + code + "; " + (node.source()) + " }"); - } - if ((ref5 = node.parent.type) === "DoWhileStatement" || ref5 === "ForInStatement") { - code = _this.traceCall(traceFunc, node.parent.loc, "code"); - node.update("{ " + code + "; " + (node.source()) + " }"); + loc = (ref = options.loc) != null ? ref : options.node.loc; + if (eventType !== "leave") { + vars = (ref1 = options.vars) != null ? ref1 : (eventType === "enter" ? this.findArguments(options.node) : this.findVariables(options.node)); + } + if (eventType === "after") { + functionCalls = (ref2 = options.functionCalls) != null ? ref2 : this.findFunctionCalls(options.node); + } + locationObj = "{ first_line: " + loc.start.line + ","; + locationObj += " first_column: " + (loc.start.column + 1) + ","; + locationObj += " last_line: " + loc.end.line + ","; + locationObj += " last_column: " + (loc.end.column + 1) + " }"; + soakify = function(name) { + if (name.indexOf(".") === -1) { + return "(typeof " + name + " === 'undefined' ? void 0 : " + name + ")"; + } else { + throw "todo"; + } + }; + extra = (function() { + switch (eventType) { + case "before": + case "after": + return "vars: [" + ((function() { + var j, len, results; + results = []; + for (j = 0, len = vars.length; j < len; j++) { + name = vars[j]; + results.push("{name: '" + name + "', value: " + (soakify(name)) + "}"); } - break; - case "ThisExpression": - case "ArrayExpression": - case "ObjectExpression": - case "FunctionExpression": - case "SequenceExpression": - case "UnaryExpression": - case "BinaryExpression": - case "AssignmentExpression": - case "UpdateExpression": - case "LogicalExpression": - case "ConditionalExpression": - case "CallExpression": - case "NewExpression": - case "MemberExpression": - case "Identifier": - case "Literal": - case "RegExpLiteral": - if ((ref6 = node.parent.type) === "IfStatement" || ref6 === "WithStatement" || ref6 === "SwitchStatement" || ref6 === "WhileStatement" || ref6 === "DoWhileStatement" || ref6 === "ForStatement" || ref6 === "SwitchCase") { - code = _this.traceCall(traceFunc, node.loc, "code"); - node.update(code + ",(" + (node.source()) + ")"); + return results; + })()) + "]"; + case "enter": + return "vars: [" + ((function() { + var j, len, results; + results = []; + for (j = 0, len = vars.length; j < len; j++) { + name = vars[j]; + results.push("{name: '" + name + "', value: " + name + "}"); } + return results; + })()) + "]"; + case "leave": + return "returnOrThrow: " + options.returnOrThrowVar; + } + })(); + if (eventType === "after") { + extra += ", functionCalls: [" + ((function() { + var j, len, results; + results = []; + for (j = 0, len = functionCalls.length; j < len; j++) { + f = functionCalls[j]; + results.push("{name: '" + f.name + "', value: " + f.tempVar + "}"); } - if (_this.needsBraces(node)) { - return node.update("{ " + (node.source()) + " }"); - } - }; - })(this)); - return result.toString(); + return results; + })()) + "]"; + } + eventObj = "{location: " + locationObj + ", type: '" + eventType + "', " + extra + "}"; + instrumentedNode = acorn.parse(this.options.traceFunc + "(" + eventObj + ");").body[0]; + instrumentedNode.pencilTracerInstrumented = true; + instrumentedNode.expression.pencilTracerInstrumented = true; + return instrumentedNode; }; - return JavaScriptInstrumenter; - - })(); - - exports.instrumentJs = function(filename, code, options) { - var instrumenter; - if (options == null) { - options = {}; - } - instrumenter = new JavaScriptInstrumenter(); - return instrumenter.instrument(filename, code, options); - }; - -}).call(this); - -},{"falafel":5}],4:[function(require,module,exports){ -// Generated by CoffeeScript 1.9.3 -(function() { - var Scope; + JavaScriptInstrumenter.prototype.createInstrumentedExpr = function(originalExpr) { + var sequenceExpr, tempVar; + tempVar = this.temporaryVariable("temp", true); + sequenceExpr = { + type: "SequenceExpression", + expressions: [] + }; + sequenceExpr.expressions.push(this.createInstrumentedNode("before", { + node: originalExpr + }).expression); + sequenceExpr.expressions.push(this.createAssignNode(tempVar, originalExpr)); + sequenceExpr.expressions.push(this.createInstrumentedNode("after", { + node: originalExpr + }).expression); + sequenceExpr.expressions.push({ + type: "Identifier", + name: tempVar + }); + return sequenceExpr; + }; - Scope = (function() { - function Scope(parent) { - this.parent = parent; - this.vars = []; - } + JavaScriptInstrumenter.prototype.createAssignNode = function(varName, expr) { + return { + type: "AssignmentExpression", + operator: "=", + left: { + type: "Identifier", + name: varName + }, + right: expr + }; + }; - Scope.prototype.add = function(variable, type) { - if (this.vars.indexOf(variable) === -1) { - return this.vars.push({ - name: variable, - type: type - }); + JavaScriptInstrumenter.prototype.findVariables = function(node, vars) { + var child, j, key, len, ref, ref1; + if (vars == null) { + vars = []; + } + if (node.type === "Identifier") { + if (vars.indexOf(node.name) === -1) { + vars.push(node.name); + } + } + for (key in node) { + if (node.type === "Property" && key === "key") { + continue; + } + if (((ref = node.type) === "FunctionExpression" || ref === "FunctionDeclaration") && key === "params") { + continue; + } + if (isArray(node[key])) { + ref1 = node[key]; + for (j = 0, len = ref1.length; j < len; j++) { + child = ref1[j]; + this.findVariables(child, vars); + } + } else if (node[key] && typeof node[key].type === "string") { + this.findVariables(node[key], vars); + } } + return vars; }; - Scope.prototype.toCode = function(activeVars) { - var code, curScope, i, isActive, len, ref, variable; - curScope = this; - code = "{"; - while (curScope) { - ref = curScope.vars; - for (i = 0, len = ref.length; i < len; i++) { - variable = ref[i]; - isActive = activeVars.indexOf(variable.name) !== -1; - code += "'" + variable.name + "': { name: '" + variable.name + "', value: " + variable.name + ", type: '" + variable.type + "', active: " + isActive + " }, "; - } - curScope = curScope.parent; + JavaScriptInstrumenter.prototype.findArguments = function(funcNode) { + var j, len, param, ref, results; + ref = funcNode.params; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + param = ref[j]; + results.push(param.name); } - code += "}"; - return code; + return results; }; - return Scope; - - })(); + JavaScriptInstrumenter.prototype.findFunctionCalls = function(node, parent, grandparent, vars) { + if (parent == null) { + parent = null; + } + if (grandparent == null) { + grandparent = null; + } + if (vars == null) { + vars = []; + } + return []; + }; - exports.Scope = Scope; + JavaScriptInstrumenter.prototype.shouldInstrumentWithBlock = function(node, parent) { + var ref; + return ((ref = node.type) === "EmptyStatement" || ref === "ExpressionStatement" || ref === "DebuggerStatement" || ref === "VariableDeclaration" || ref === "FunctionDeclaration") && !(parent.type === "ForStatement" && parent.init === node) && !(parent.type === "ForInStatement" && parent.left === node); + }; -}).call(this); + JavaScriptInstrumenter.prototype.shouldInstrumentExpr = function(node, parent) { + return (parent.type === "IfStatement" && parent.test === node) || (parent.type === "WithStatement" && parent.object === node) || (parent.type === "SwitchStatement" && parent.discriminant === node) || (parent.type === "WhileStatement" && parent.test === node) || (parent.type === "DoWhileStatement" && parent.test === node) || (parent.type === "ForStatement" && parent.test === node) || (parent.type === "ForStatement" && parent.update === node) || (parent.type === "SwitchCase" && parent.test === node); + }; -},{}],5:[function(require,module,exports){ -var parse = require('acorn').parse; - -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) keys.push(key); - return keys; -}; -var forEach = function (xs, fn) { - if (xs.forEach) return xs.forEach(fn); - for (var i = 0; i < xs.length; i++) { - fn.call(xs, xs[i], i, xs); - } -}; - -var isArray = Array.isArray || function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; -}; + JavaScriptInstrumenter.prototype.mapChildren = function(node, func) { + var child, i, key, results; + results = []; + for (key in node) { + if (isArray(node[key])) { + results.push((function() { + var j, len, ref, results1; + ref = node[key]; + results1 = []; + for (i = j = 0, len = ref.length; j < len; i = ++j) { + child = ref[i]; + results1.push(node[key][i] = func(child)); + } + return results1; + })()); + } else if (node[key] && node[key].type) { + results.push(node[key] = func(node[key])); + } else { + results.push(void 0); + } + } + return results; + }; -module.exports = function (src, opts, fn) { - if (typeof opts === 'function') { - fn = opts; - opts = {}; - } - if (typeof src === 'object') { - opts = src; - src = opts.source; - delete opts.source; - } - src = src === undefined ? opts.source : src; - if (typeof src !== 'string') src = String(src); - var ast = parse(src, opts); - - var result = { - chunks : src.split(''), - toString : function () { return result.chunks.join('') }, - inspect : function () { return result.toString() } + JavaScriptInstrumenter.prototype.instrumentTree = function(node, parent, returnOrThrowVar) { + var ref; + if (parent == null) { + parent = null; + } + if ((ref = node.type) === "FunctionDeclaration" || ref === "FunctionExpression") { + returnOrThrowVar = this.temporaryVariable("returnOrThrow"); + } + return this.mapChildren(node, (function(_this) { + return function(child) { + var newBlock, ref1, tryStatement; + _this.instrumentTree(child, node, returnOrThrowVar); + if (_this.shouldInstrumentWithBlock(child, node)) { + return { + type: "BlockStatement", + body: [ + _this.createInstrumentedNode("before", { + node: child + }), child, _this.createInstrumentedNode("after", { + node: child + }) + ] + }; + } else if (_this.shouldInstrumentExpr(child, node)) { + return _this.createInstrumentedExpr(child); + } else if (((ref1 = node.type) === "FunctionDeclaration" || ref1 === "FunctionExpression") && node.body === child) { + newBlock = acorn.parse("{\n var " + returnOrThrowVar + " = { type: 'return', value: void 0 };\n try {}\n catch (" + _this.caughtErrorVar + ") {\n " + returnOrThrowVar + ".type = 'throw';\n " + returnOrThrowVar + ".value = " + _this.caughtErrorVar + ";\n throw " + _this.caughtErrorVar + ";\n } finally {}\n}").body[0]; + tryStatement = newBlock.body[1]; + tryStatement.block = child; + newBlock.body.unshift(_this.createInstrumentedNode("enter", { + node: node + })); + tryStatement.finalizer.body.unshift(_this.createInstrumentedNode("leave", { + node: node, + returnOrThrowVar: returnOrThrowVar + })); + return newBlock; + } else { + return child; + } + }; + })(this)); }; - var index = 0; - - (function walk (node, parent) { - insertHelpers(node, parent, result.chunks); - - forEach(objectKeys(node), function (key) { - if (key === 'parent') return; - - var child = node[key]; - if (isArray(child)) { - forEach(child, function (c) { - if (c && typeof c.type === 'string') { - walk(c, node); - } - }); + + JavaScriptInstrumenter.prototype.instrument = function(filename, code) { + var ast, name, tempVarsDeclaration; + this.undeclaredVars = []; + this.referencedVars = []; + ast = acorn.parse(code, { + locations: true, + onToken: (function(_this) { + return function(token) { + if (token.type.label === "name" && _this.referencedVars.indexOf(token.value) === -1) { + return _this.referencedVars.push(token.value); } - else if (child && typeof child.type === 'string') { - walk(child, node); + }; + })(this) + }); + this.caughtErrorVar = this.temporaryVariable("err"); + this.instrumentTree(ast); + if (this.undeclaredVars.length > 0) { + tempVarsDeclaration = { + type: "VariableDeclaration", + kind: "var", + declarations: (function() { + var j, len, ref, results; + ref = this.undeclaredVars; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + name = ref[j]; + results.push({ + type: "VariableDeclarator", + id: { + type: "Identifier", + name: name + }, + init: null + }); } - }); - fn(node); - })(ast, undefined); - - return result; -}; - -function insertHelpers (node, parent, chunks) { - node.parent = parent; - - node.source = function () { - return chunks.slice(node.start, node.end).join(''); + return results; + }).call(this) + }; + ast.body.unshift(tempVarsDeclaration); + } + if (this.options.ast) { + return ast; + } + return escodegen.generate(ast); }; - - if (node.update && typeof node.update === 'object') { - var prev = node.update; - forEach(objectKeys(prev), function (key) { - update[key] = prev[key]; - }); - node.update = update; - } - else { - node.update = update; - } - - function update (s) { - chunks[node.start] = s; - for (var i = node.start + 1; i < node.end; i++) { - chunks[i] = ''; - } + + return JavaScriptInstrumenter; + + })(); + + exports.instrumentJs = function(filename, code, options) { + var instrumenter; + if (options == null) { + options = {}; } -} + instrumenter = new JavaScriptInstrumenter(options); + return instrumenter.instrument(filename, code); + }; + +}).call(this); -},{"acorn":6}],6:[function(require,module,exports){ +},{"acorn":4,"escodegen":7}],4:[function(require,module,exports){ (function (global){ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.acorn = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 6 && (prop.computed || prop.method || prop.shorthand)) return; + var key = prop.key, + name = undefined; + switch (key.type) { + case "Identifier": + name = key.name;break; + case "Literal": + name = String(key.value);break; + default: + return; + } + var kind = prop.kind; + if (this.options.ecmaVersion >= 6) { + if (name === "__proto__" && kind === "init") { + if (propHash.proto) this.raise(key.start, "Redefinition of __proto__ property"); + propHash.proto = true; + } + return; + } + var other = undefined; + if (_util.has(propHash, name)) { + other = propHash[name]; + var isGetSet = kind !== "init"; + if ((this.strict || isGetSet) && other[kind] || !(isGetSet ^ other.init)) this.raise(key.start, "Redefinition of property"); + } else { + other = propHash[name] = { + init: false, + get: false, + set: false + }; + } + other[kind] = true; +}; -_dereq_("./lval"); +// ### Expression parsing -_dereq_("./expression"); +// These nest, from the most general expression type at the top to +// 'atomic', nondivisible expression types at the bottom. Most of +// the functions will simply let the function(s) below them parse, +// and, *if* the syntactic construct they handle is present, wrap +// the AST node that the inner parser gave them in another node. -exports.Parser = _state.Parser; -exports.plugins = _state.plugins; -exports.defaultOptions = _options.defaultOptions; +// Parse a full expression. The optional arguments are used to +// forbid the `in` operator (in for loops initalization expressions) +// and provide reference for storing '=' operator inside shorthand +// property assignment in contexts where both object expression +// and object pattern might appear (so it's possible to raise +// delayed syntax error at correct position). -var _location = _dereq_("./location"); +pp.parseExpression = function (noIn, refShorthandDefaultPos) { + var startPos = this.start, + startLoc = this.startLoc; + var expr = this.parseMaybeAssign(noIn, refShorthandDefaultPos); + if (this.type === _tokentype.types.comma) { + var node = this.startNodeAt(startPos, startLoc); + node.expressions = [expr]; + while (this.eat(_tokentype.types.comma)) node.expressions.push(this.parseMaybeAssign(noIn, refShorthandDefaultPos)); + return this.finishNode(node, "SequenceExpression"); + } + return expr; +}; -exports.SourceLocation = _location.SourceLocation; -exports.getLineInfo = _location.getLineInfo; -exports.Node = _dereq_("./node").Node; +// Parse an assignment expression. This includes applications of +// operators like `+=`. -var _tokentype = _dereq_("./tokentype"); +pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse) { + if (this.type == _tokentype.types._yield && this.inGenerator) return this.parseYield(); -exports.TokenType = _tokentype.TokenType; -exports.tokTypes = _tokentype.types; + var failOnShorthandAssign = undefined; + if (!refShorthandDefaultPos) { + refShorthandDefaultPos = { start: 0 }; + failOnShorthandAssign = true; + } else { + failOnShorthandAssign = false; + } + var startPos = this.start, + startLoc = this.startLoc; + if (this.type == _tokentype.types.parenL || this.type == _tokentype.types.name) this.potentialArrowAt = this.start; + var left = this.parseMaybeConditional(noIn, refShorthandDefaultPos); + if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc); + if (this.type.isAssign) { + var node = this.startNodeAt(startPos, startLoc); + node.operator = this.value; + node.left = this.type === _tokentype.types.eq ? this.toAssignable(left) : left; + refShorthandDefaultPos.start = 0; // reset because shorthand default was used correctly + this.checkLVal(left); + this.next(); + node.right = this.parseMaybeAssign(noIn); + return this.finishNode(node, "AssignmentExpression"); + } else if (failOnShorthandAssign && refShorthandDefaultPos.start) { + this.unexpected(refShorthandDefaultPos.start); + } + return left; +}; -var _tokencontext = _dereq_("./tokencontext"); +// Parse a ternary conditional (`?:`) operator. -exports.TokContext = _tokencontext.TokContext; -exports.tokContexts = _tokencontext.types; +pp.parseMaybeConditional = function (noIn, refShorthandDefaultPos) { + var startPos = this.start, + startLoc = this.startLoc; + var expr = this.parseExprOps(noIn, refShorthandDefaultPos); + if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; + if (this.eat(_tokentype.types.question)) { + var node = this.startNodeAt(startPos, startLoc); + node.test = expr; + node.consequent = this.parseMaybeAssign(); + this.expect(_tokentype.types.colon); + node.alternate = this.parseMaybeAssign(noIn); + return this.finishNode(node, "ConditionalExpression"); + } + return expr; +}; -var _identifier = _dereq_("./identifier"); +// Start the precedence parser. -exports.isIdentifierChar = _identifier.isIdentifierChar; -exports.isIdentifierStart = _identifier.isIdentifierStart; -exports.Token = _dereq_("./tokenize").Token; +pp.parseExprOps = function (noIn, refShorthandDefaultPos) { + var startPos = this.start, + startLoc = this.startLoc; + var expr = this.parseMaybeUnary(refShorthandDefaultPos); + if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; + return this.parseExprOp(expr, startPos, startLoc, -1, noIn); +}; -var _whitespace = _dereq_("./whitespace"); +// Parse binary operators with the operator precedence parsing +// algorithm. `left` is the left-hand side of the operator. +// `minPrec` provides context that allows the function to stop and +// defer further parser to one of its callers when it encounters an +// operator that has a lower precedence than the set it is parsing. -exports.isNewLine = _whitespace.isNewLine; -exports.lineBreak = _whitespace.lineBreak; -exports.lineBreakG = _whitespace.lineBreakG; -var version = "1.2.2";exports.version = version; +pp.parseExprOp = function (left, leftStartPos, leftStartLoc, minPrec, noIn) { + var prec = this.type.binop; + if (prec != null && (!noIn || this.type !== _tokentype.types._in)) { + if (prec > minPrec) { + var node = this.startNodeAt(leftStartPos, leftStartLoc); + node.left = left; + node.operator = this.value; + var op = this.type; + this.next(); + var startPos = this.start, + startLoc = this.startLoc; + node.right = this.parseExprOp(this.parseMaybeUnary(), startPos, startLoc, prec, noIn); + this.finishNode(node, op === _tokentype.types.logicalOR || op === _tokentype.types.logicalAND ? "LogicalExpression" : "BinaryExpression"); + return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn); + } + } + return left; +}; -function parse(input, options) { - var p = parser(options, input); - var startPos = p.pos, - startLoc = p.options.locations && p.curPosition(); - p.nextToken(); - return p.parseTopLevel(p.options.program || p.startNodeAt(startPos, startLoc)); -} +// Parse unary operators, both prefix and postfix. -function parseExpressionAt(input, pos, options) { - var p = parser(options, input, pos); - p.nextToken(); - return p.parseExpression(); -} +pp.parseMaybeUnary = function (refShorthandDefaultPos) { + if (this.type.prefix) { + var node = this.startNode(), + update = this.type === _tokentype.types.incDec; + node.operator = this.value; + node.prefix = true; + this.next(); + node.argument = this.parseMaybeUnary(); + if (refShorthandDefaultPos && refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start); + if (update) this.checkLVal(node.argument);else if (this.strict && node.operator === "delete" && node.argument.type === "Identifier") this.raise(node.start, "Deleting local variable in strict mode"); + return this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression"); + } + var startPos = this.start, + startLoc = this.startLoc; + var expr = this.parseExprSubscripts(refShorthandDefaultPos); + if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; + while (this.type.postfix && !this.canInsertSemicolon()) { + var node = this.startNodeAt(startPos, startLoc); + node.operator = this.value; + node.prefix = false; + node.argument = expr; + this.checkLVal(expr); + this.next(); + expr = this.finishNode(node, "UpdateExpression"); + } + return expr; +}; -function tokenizer(input, options) { - return parser(options, input); -} +// Parse call, dot, and `[]`-subscript expressions. -function parser(options, input) { - return new Parser(getOptions(options), String(input)); -} +pp.parseExprSubscripts = function (refShorthandDefaultPos) { + var startPos = this.start, + startLoc = this.startLoc; + var expr = this.parseExprAtom(refShorthandDefaultPos); + if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; + return this.parseSubscripts(expr, startPos, startLoc); +}; -},{"./expression":6,"./identifier":7,"./location":8,"./lval":9,"./node":10,"./options":11,"./parseutil":12,"./state":13,"./statement":14,"./tokencontext":15,"./tokenize":16,"./tokentype":17,"./whitespace":19}],2:[function(_dereq_,module,exports){ -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor +pp.parseSubscripts = function (base, startPos, startLoc, noCalls) { + for (;;) { + if (this.eat(_tokentype.types.dot)) { + var node = this.startNodeAt(startPos, startLoc); + node.object = base; + node.property = this.parseIdent(true); + node.computed = false; + base = this.finishNode(node, "MemberExpression"); + } else if (this.eat(_tokentype.types.bracketL)) { + var node = this.startNodeAt(startPos, startLoc); + node.object = base; + node.property = this.parseExpression(); + node.computed = true; + this.expect(_tokentype.types.bracketR); + base = this.finishNode(node, "MemberExpression"); + } else if (!noCalls && this.eat(_tokentype.types.parenL)) { + var node = this.startNodeAt(startPos, startLoc); + node.callee = base; + node.arguments = this.parseExprList(_tokentype.types.parenR, false); + base = this.finishNode(node, "CallExpression"); + } else if (this.type === _tokentype.types.backQuote) { + var node = this.startNodeAt(startPos, startLoc); + node.tag = base; + node.quasi = this.parseTemplate(); + base = this.finishNode(node, "TaggedTemplateExpression"); + } else { + return base; + } } -} +}; -},{}],3:[function(_dereq_,module,exports){ -// shim for using process in browser +// Parse an atomic expression — either a single token that is an +// expression, an expression started by a keyword like `function` or +// `new`, or an expression wrapped in punctuation like `()`, `[]`, +// or `{}`. -var process = module.exports = {}; -var queue = []; -var draining = false; +pp.parseExprAtom = function (refShorthandDefaultPos) { + var node = undefined, + canBeArrow = this.potentialArrowAt == this.start; + switch (this.type) { + case _tokentype.types._super: + if (!this.inFunction) this.raise(this.start, "'super' outside of function or class"); + case _tokentype.types._this: + var type = this.type === _tokentype.types._this ? "ThisExpression" : "Super"; + node = this.startNode(); + this.next(); + return this.finishNode(node, type); -function drainQueue() { - if (draining) { - return; - } - draining = true; - var currentQueue; - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - var i = -1; - while (++i < len) { - currentQueue[i](); - } - len = queue.length; - } - draining = false; -} -process.nextTick = function (fun) { - queue.push(fun); - if (!draining) { - setTimeout(drainQueue, 0); - } -}; + case _tokentype.types._yield: + if (this.inGenerator) this.unexpected(); -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; + case _tokentype.types.name: + var startPos = this.start, + startLoc = this.startLoc; + var id = this.parseIdent(this.type !== _tokentype.types.name); + if (canBeArrow && !this.canInsertSemicolon() && this.eat(_tokentype.types.arrow)) return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id]); + return id; -function noop() {} + case _tokentype.types.regexp: + var value = this.value; + node = this.parseLiteral(value.value); + node.regex = { pattern: value.pattern, flags: value.flags }; + return node; -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; + case _tokentype.types.num:case _tokentype.types.string: + return this.parseLiteral(this.value); -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; + case _tokentype.types._null:case _tokentype.types._true:case _tokentype.types._false: + node = this.startNode(); + node.value = this.type === _tokentype.types._null ? null : this.type === _tokentype.types._true; + node.raw = this.type.keyword; + this.next(); + return this.finishNode(node, "Literal"); -// TODO(shtylman) -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; + case _tokentype.types.parenL: + return this.parseParenAndDistinguishExpression(canBeArrow); -},{}],4:[function(_dereq_,module,exports){ -module.exports = function isBuffer(arg) { - return arg && typeof arg === 'object' - && typeof arg.copy === 'function' - && typeof arg.fill === 'function' - && typeof arg.readUInt8 === 'function'; -} -},{}],5:[function(_dereq_,module,exports){ -(function (process,global){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. + case _tokentype.types.bracketL: + node = this.startNode(); + this.next(); + // check whether this is array comprehension or regular array + if (this.options.ecmaVersion >= 7 && this.type === _tokentype.types._for) { + return this.parseComprehension(node, false); + } + node.elements = this.parseExprList(_tokentype.types.bracketR, true, true, refShorthandDefaultPos); + return this.finishNode(node, "ArrayExpression"); -var formatRegExp = /%[sdj%]/g; -exports.format = function(f) { - if (!isString(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); - } - return objects.join(' '); - } + case _tokentype.types.braceL: + return this.parseObj(false, refShorthandDefaultPos); - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; - } - default: - return x; - } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); - } + case _tokentype.types._function: + node = this.startNode(); + this.next(); + return this.parseFunction(node, false); + + case _tokentype.types._class: + return this.parseClass(this.startNode(), false); + + case _tokentype.types._new: + return this.parseNew(); + + case _tokentype.types.backQuote: + return this.parseTemplate(); + + default: + this.unexpected(); } - return str; }; +pp.parseLiteral = function (value) { + var node = this.startNode(); + node.value = value; + node.raw = this.input.slice(this.start, this.end); + this.next(); + return this.finishNode(node, "Literal"); +}; + +pp.parseParenExpression = function () { + this.expect(_tokentype.types.parenL); + var val = this.parseExpression(); + this.expect(_tokentype.types.parenR); + return val; +}; -// Mark that a method should not be used. -// Returns a modified function which warns once by default. -// If --no-deprecation is set, then it is a no-op. -exports.deprecate = function(fn, msg) { - // Allow for deprecating things in the process of starting up. - if (isUndefined(global.process)) { - return function() { - return exports.deprecate(fn, msg).apply(this, arguments); - }; - } +pp.parseParenAndDistinguishExpression = function (canBeArrow) { + var startPos = this.start, + startLoc = this.startLoc, + val = undefined; + if (this.options.ecmaVersion >= 6) { + this.next(); - if (process.noDeprecation === true) { - return fn; - } + if (this.options.ecmaVersion >= 7 && this.type === _tokentype.types._for) { + return this.parseComprehension(this.startNodeAt(startPos, startLoc), true); + } - var warned = false; - function deprecated() { - if (!warned) { - if (process.throwDeprecation) { - throw new Error(msg); - } else if (process.traceDeprecation) { - console.trace(msg); + var innerStartPos = this.start, + innerStartLoc = this.startLoc; + var exprList = [], + first = true; + var refShorthandDefaultPos = { start: 0 }, + spreadStart = undefined, + innerParenStart = undefined; + while (this.type !== _tokentype.types.parenR) { + first ? first = false : this.expect(_tokentype.types.comma); + if (this.type === _tokentype.types.ellipsis) { + spreadStart = this.start; + exprList.push(this.parseParenItem(this.parseRest())); + break; } else { - console.error(msg); + if (this.type === _tokentype.types.parenL && !innerParenStart) { + innerParenStart = this.start; + } + exprList.push(this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem)); } - warned = true; } - return fn.apply(this, arguments); - } + var innerEndPos = this.start, + innerEndLoc = this.startLoc; + this.expect(_tokentype.types.parenR); - return deprecated; -}; + if (canBeArrow && !this.canInsertSemicolon() && this.eat(_tokentype.types.arrow)) { + if (innerParenStart) this.unexpected(innerParenStart); + return this.parseParenArrowList(startPos, startLoc, exprList); + } + if (!exprList.length) this.unexpected(this.lastTokStart); + if (spreadStart) this.unexpected(spreadStart); + if (refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start); -var debugs = {}; -var debugEnviron; -exports.debuglog = function(set) { - if (isUndefined(debugEnviron)) - debugEnviron = process.env.NODE_DEBUG || ''; - set = set.toUpperCase(); - if (!debugs[set]) { - if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { - var pid = process.pid; - debugs[set] = function() { - var msg = exports.format.apply(exports, arguments); - console.error('%s %d: %s', set, pid, msg); - }; + if (exprList.length > 1) { + val = this.startNodeAt(innerStartPos, innerStartLoc); + val.expressions = exprList; + this.finishNodeAt(val, "SequenceExpression", innerEndPos, innerEndLoc); } else { - debugs[set] = function() {}; + val = exprList[0]; } + } else { + val = this.parseParenExpression(); + } + + if (this.options.preserveParens) { + var par = this.startNodeAt(startPos, startLoc); + par.expression = val; + return this.finishNode(par, "ParenthesizedExpression"); + } else { + return val; } - return debugs[set]; }; +pp.parseParenItem = function (item) { + return item; +}; -/** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. - */ -/* legacy: obj, showHidden, depth, colors*/ -function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); -} -exports.inspect = inspect; - - -// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics -inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] -}; - -// Don't use 'blue' not visible on cmd.exe -inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' -}; - - -function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; - - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; - } -} - - -function stylizeNoColor(str, styleType) { - return str; -} - +pp.parseParenArrowList = function (startPos, startLoc, exprList) { + return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList); +}; -function arrayToHash(array) { - var hash = {}; +// New's precedence is slightly tricky. It must allow its argument +// to be a `[]` or dot subscript expression, but not a call — at +// least, not without wrapping it in parentheses. Thus, it uses the - array.forEach(function(val, idx) { - hash[val] = true; - }); +var empty = []; - return hash; -} +pp.parseNew = function () { + var node = this.startNode(); + var meta = this.parseIdent(true); + if (this.options.ecmaVersion >= 6 && this.eat(_tokentype.types.dot)) { + node.meta = meta; + node.property = this.parseIdent(true); + if (node.property.name !== "target") this.raise(node.property.start, "The only valid meta property for new is new.target"); + return this.finishNode(node, "MetaProperty"); + } + var startPos = this.start, + startLoc = this.startLoc; + node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true); + if (this.eat(_tokentype.types.parenL)) node.arguments = this.parseExprList(_tokentype.types.parenR, false);else node.arguments = empty; + return this.finishNode(node, "NewExpression"); +}; +// Parse template expression. -function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString(ret)) { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } +pp.parseTemplateElement = function () { + var elem = this.startNode(); + elem.value = { + raw: this.input.slice(this.start, this.end).replace(/\r\n?/g, "\n"), + cooked: this.value + }; + this.next(); + elem.tail = this.type === _tokentype.types.backQuote; + return this.finishNode(elem, "TemplateElement"); +}; - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; +pp.parseTemplate = function () { + var node = this.startNode(); + this.next(); + node.expressions = []; + var curElt = this.parseTemplateElement(); + node.quasis = [curElt]; + while (!curElt.tail) { + this.expect(_tokentype.types.dollarBraceL); + node.expressions.push(this.parseExpression()); + this.expect(_tokentype.types.braceR); + node.quasis.push(curElt = this.parseTemplateElement()); } + this.next(); + return this.finishNode(node, "TemplateLiteral"); +}; - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); +// Parse an object literal or binding pattern. - if (ctx.showHidden) { - keys = Object.getOwnPropertyNames(value); - } +pp.parseObj = function (isPattern, refShorthandDefaultPos) { + var node = this.startNode(), + first = true, + propHash = {}; + node.properties = []; + this.next(); + while (!this.eat(_tokentype.types.braceR)) { + if (!first) { + this.expect(_tokentype.types.comma); + if (this.afterTrailingComma(_tokentype.types.braceR)) break; + } else first = false; - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); + var prop = this.startNode(), + isGenerator = undefined, + startPos = undefined, + startLoc = undefined; + if (this.options.ecmaVersion >= 6) { + prop.method = false; + prop.shorthand = false; + if (isPattern || refShorthandDefaultPos) { + startPos = this.start; + startLoc = this.startLoc; + } + if (!isPattern) isGenerator = this.eat(_tokentype.types.star); + } + this.parsePropertyName(prop); + this.parsePropertyValue(prop, isPattern, isGenerator, startPos, startLoc, refShorthandDefaultPos); + this.checkPropClash(prop, propHash); + node.properties.push(this.finishNode(prop, "Property")); } + return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression"); +}; - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); +pp.parsePropertyValue = function (prop, isPattern, isGenerator, startPos, startLoc, refShorthandDefaultPos) { + if (this.eat(_tokentype.types.colon)) { + prop.value = isPattern ? this.parseMaybeDefault(this.start, this.startLoc) : this.parseMaybeAssign(false, refShorthandDefaultPos); + prop.kind = "init"; + } else if (this.options.ecmaVersion >= 6 && this.type === _tokentype.types.parenL) { + if (isPattern) this.unexpected(); + prop.kind = "init"; + prop.method = true; + prop.value = this.parseMethod(isGenerator); + } else if (this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" && (prop.key.name === "get" || prop.key.name === "set") && (this.type != _tokentype.types.comma && this.type != _tokentype.types.braceR)) { + if (isGenerator || isPattern) this.unexpected(); + prop.kind = prop.key.name; + this.parsePropertyName(prop); + prop.value = this.parseMethod(false); + var paramCount = prop.kind === "get" ? 0 : 1; + if (prop.value.params.length !== paramCount) { + var start = prop.value.start; + if (prop.kind === "get") this.raise(start, "getter should have no params");else this.raise(start, "setter should have exactly one param"); } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") { + prop.kind = "init"; + if (isPattern) { + if (this.isKeyword(prop.key.name) || this.strict && (_identifier.reservedWords.strictBind(prop.key.name) || _identifier.reservedWords.strict(prop.key.name)) || !this.options.allowReserved && this.isReservedWord(prop.key.name)) this.raise(prop.key.start, "Binding " + prop.key.name); + prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key); + } else if (this.type === _tokentype.types.eq && refShorthandDefaultPos) { + if (!refShorthandDefaultPos.start) refShorthandDefaultPos.start = this.start; + prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key); + } else { + prop.value = prop.key; } - if (isError(value)) { - return formatError(value); + prop.shorthand = true; + } else this.unexpected(); +}; + +pp.parsePropertyName = function (prop) { + if (this.options.ecmaVersion >= 6) { + if (this.eat(_tokentype.types.bracketL)) { + prop.computed = true; + prop.key = this.parseMaybeAssign(); + this.expect(_tokentype.types.bracketR); + return prop.key; + } else { + prop.computed = false; } } + return prop.key = this.type === _tokentype.types.num || this.type === _tokentype.types.string ? this.parseExprAtom() : this.parseIdent(true); +}; - var base = '', array = false, braces = ['{', '}']; - - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; - } +// Initialize empty function node. - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; +pp.initFunction = function (node) { + node.id = null; + if (this.options.ecmaVersion >= 6) { + node.generator = false; + node.expression = false; } +}; - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } +// Parse object or class method. - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); +pp.parseMethod = function (isGenerator) { + var node = this.startNode(); + this.initFunction(node); + this.expect(_tokentype.types.parenL); + node.params = this.parseBindingList(_tokentype.types.parenR, false, false); + var allowExpressionBody = undefined; + if (this.options.ecmaVersion >= 6) { + node.generator = isGenerator; } + this.parseFunctionBody(node, false); + return this.finishNode(node, "FunctionExpression"); +}; - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); - } +// Parse arrow function expression with given parameters. - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } +pp.parseArrowExpression = function (node, params) { + this.initFunction(node); + node.params = this.toAssignableList(params, true); + this.parseFunctionBody(node, true); + return this.finishNode(node, "ArrowFunctionExpression"); +}; - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } - } +// Parse function body and check parameters. - ctx.seen.push(value); +pp.parseFunctionBody = function (node, allowExpression) { + var isExpression = allowExpression && this.type !== _tokentype.types.braceL; - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + if (isExpression) { + node.body = this.parseMaybeAssign(); + node.expression = true; } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); + // Start a new scope with regard to labels and the `inFunction` + // flag (restore them to their old value afterwards). + var oldInFunc = this.inFunction, + oldInGen = this.inGenerator, + oldLabels = this.labels; + this.inFunction = true;this.inGenerator = node.generator;this.labels = []; + node.body = this.parseBlock(true); + node.expression = false; + this.inFunction = oldInFunc;this.inGenerator = oldInGen;this.labels = oldLabels; } - ctx.seen.pop(); + // If this is a strict mode function, verify that argument names + // are not repeated, and it does not try to bind the words `eval` + // or `arguments`. + if (this.strict || !isExpression && node.body.body.length && this.isUseStrict(node.body.body[0])) { + var nameHash = {}, + oldStrict = this.strict; + this.strict = true; + if (node.id) this.checkLVal(node.id, true); + for (var i = 0; i < node.params.length; i++) { + this.checkLVal(node.params[i], true, nameHash); + }this.strict = oldStrict; + } +}; - return reduceToSingleString(output, base, braces); -} +// Parses a comma-separated list of expressions, and returns them as +// an array. `close` is the token type that ends the list, and +// `allowEmpty` can be turned on to allow subsequent commas with +// nothing in between them to be parsed as `null` (which is needed +// for array literals). +pp.parseExprList = function (close, allowTrailingComma, allowEmpty, refShorthandDefaultPos) { + var elts = [], + first = true; + while (!this.eat(close)) { + if (!first) { + this.expect(_tokentype.types.comma); + if (allowTrailingComma && this.afterTrailingComma(close)) break; + } else first = false; -function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); + var elt = undefined; + if (allowEmpty && this.type === _tokentype.types.comma) elt = null;else if (this.type === _tokentype.types.ellipsis) elt = this.parseSpread(refShorthandDefaultPos);else elt = this.parseMaybeAssign(false, refShorthandDefaultPos); + elts.push(elt); } - if (isNumber(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); -} - - -function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; -} + return elts; +}; +// Parse the next token as an identifier. If `liberal` is true (used +// when parsing properties), it will also convert keywords into +// identifiers. -function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } +pp.parseIdent = function (liberal) { + var node = this.startNode(); + if (liberal && this.options.allowReserved == "never") liberal = false; + if (this.type === _tokentype.types.name) { + if (!liberal && (!this.options.allowReserved && this.isReservedWord(this.value) || this.strict && _identifier.reservedWords.strict(this.value) && (this.options.ecmaVersion >= 6 || this.input.slice(this.start, this.end).indexOf("\\") == -1))) this.raise(this.start, "The keyword '" + this.value + "' is reserved"); + node.name = this.value; + } else if (liberal && this.type.keyword) { + node.name = this.type.keyword; + } else { + this.unexpected(); } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; -} + this.next(); + return this.finishNode(node, "Identifier"); +}; +// Parses yield expression inside generator. -function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } +pp.parseYield = function () { + var node = this.startNode(); + this.next(); + if (this.type == _tokentype.types.semi || this.canInsertSemicolon() || this.type != _tokentype.types.star && !this.type.startsExpr) { + node.delegate = false; + node.argument = null; } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - if (!hasOwnProperty(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } + node.delegate = this.eat(_tokentype.types.star); + node.argument = this.parseMaybeAssign(); } + return this.finishNode(node, "YieldExpression"); +}; - return name + ': ' + str; -} - +// Parses array and generator comprehensions. -function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); - - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; +pp.parseComprehension = function (node, isGenerator) { + node.blocks = []; + while (this.type === _tokentype.types._for) { + var block = this.startNode(); + this.next(); + this.expect(_tokentype.types.parenL); + block.left = this.parseBindingAtom(); + this.checkLVal(block.left, true); + this.expectContextual("of"); + block.right = this.parseExpression(); + this.expect(_tokentype.types.parenR); + node.blocks.push(this.finishNode(block, "ComprehensionBlock")); } + node.filter = this.eat(_tokentype.types._if) ? this.parseParenExpression() : null; + node.body = this.parseExpression(); + this.expect(isGenerator ? _tokentype.types.parenR : _tokentype.types.bracketR); + node.generator = isGenerator; + return this.finishNode(node, "ComprehensionExpression"); +}; - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; -} +},{"./identifier":2,"./state":10,"./tokentype":14,"./util":15}],2:[function(_dereq_,module,exports){ +// This is a trick taken from Esprima. It turns out that, on +// non-Chrome browsers, to check whether a string is in a set, a +// predicate containing a big ugly `switch` statement is faster than +// a regular expression, and on Chrome the two are about on par. +// This function uses `eval` (non-lexical) to produce such a +// predicate from a space-separated string of words. +// +// It starts by sorting the words by length. +"use strict"; -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. -function isArray(ar) { - return Array.isArray(ar); -} -exports.isArray = isArray; +exports.__esModule = true; +exports.isIdentifierStart = isIdentifierStart; +exports.isIdentifierChar = isIdentifierChar; +function makePredicate(words) { + words = words.split(" "); + var f = "", + cats = []; + out: for (var i = 0; i < words.length; ++i) { + for (var j = 0; j < cats.length; ++j) { + if (cats[j][0].length == words[i].length) { + cats[j].push(words[i]); + continue out; + } + }cats.push([words[i]]); + } + function compareTo(arr) { + if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";"; + f += "switch(str){"; + for (var i = 0; i < arr.length; ++i) { + f += "case " + JSON.stringify(arr[i]) + ":"; + }f += "return true}return false;"; + } -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; + // When there are more than three length categories, an outer + // switch first dispatches on the lengths, to save on comparisons. -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; + if (cats.length > 3) { + cats.sort(function (a, b) { + return b.length - a.length; + }); + f += "switch(str.length){"; + for (var i = 0; i < cats.length; ++i) { + var cat = cats[i]; + f += "case " + cat[0].length + ":"; + compareTo(cat); + } + f += "}" -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; + // Otherwise, simply generate a flat `switch` statement. -function isNumber(arg) { - return typeof arg === 'number'; + ; + } else { + compareTo(words); + } + return new Function("str", f); } -exports.isNumber = isNumber; -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; +// Reserved word lists for various dialects of the language -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; +var reservedWords = { + 3: makePredicate("abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile"), + 5: makePredicate("class enum extends super const export import"), + 6: makePredicate("enum await"), + strict: makePredicate("implements interface let package private protected public static yield"), + strictBind: makePredicate("eval arguments") +}; -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; +exports.reservedWords = reservedWords; +// And the keywords -function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; +var ecma5AndLessKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this"; -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -exports.isObject = isObject; +var keywords = { + 5: makePredicate(ecma5AndLessKeywords), + 6: makePredicate(ecma5AndLessKeywords + " let const class extends export import yield super") +}; -function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; +exports.keywords = keywords; +// ## Character categories -function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; +// Big ugly regular expressions that match characters in the +// whitespace, identifier, and identifier-start categories. These +// are only applied when a character is found to actually have a +// code point above 128. +// Generated by `tools/generate-identifier-regex.js`. -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; - -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; +var nonASCIIidentifierStartChars = "ªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽͿΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠ-ࢲऄ-हऽॐक़-ॡॱ-ঀঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-హఽౘౙౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൠൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛮ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᧁ-ᧇᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕ℘-ℝℤΩℨK-ℹℼ-ℿⅅ-ⅉⅎⅠ-ↈⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞ々-〇〡-〩〱-〵〸-〼ぁ-ゖ゛-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚝꚠ-ꛯꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞭꞰꞱꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꩾ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭟꭤꭥꯀ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ"; +var nonASCIIidentifierChars = "‌‍·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-٩ٰۖ-ۜ۟-۪ۤۧۨ-ۭ۰-۹ܑܰ-݊ަ-ް߀-߉߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣤ-ःऺ-़ा-ॏ॑-ॗॢॣ०-९ঁ-ঃ়া-ৄেৈো-্ৗৢৣ০-৯ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑ੦-ੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣ૦-૯ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣ୦-୯ஂா-ூெ-ைொ-்ௗ௦-௯ఀ-ఃా-ౄె-ైొ-్ౕౖౢౣ౦-౯ಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣ೦-೯ഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣ൦-൯ංඃ්ා-ුූෘ-ෟ෦-෯ෲෳัิ-ฺ็-๎๐-๙ັິ-ູົຼ່-ໍ໐-໙༘༙༠-༩༹༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှ၀-၉ၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏ-ႝ፝-፟፩-፱ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝០-៩᠋-᠍᠐-᠙ᢩᤠ-ᤫᤰ-᤻᥆-᥏ᦰ-ᧀᧈᧉ᧐-᧚ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼-᪉᪐-᪙᪰-᪽ᬀ-ᬄ᬴-᭄᭐-᭙᭫-᭳ᮀ-ᮂᮡ-ᮭ᮰-᮹᯦-᯳ᰤ-᰷᱀-᱉᱐-᱙᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷼-᷿‿⁀⁔⃐-⃥⃜⃡-⃰⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꘠-꘩꙯ꙴ-꙽ꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-꣄꣐-꣙꣠-꣱꤀-꤉ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀꧐-꧙ꧥ꧰-꧹ꨩ-ꨶꩃꩌꩍ꩐-꩙ꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭꯰-꯹ﬞ︀-️︠-︭︳︴﹍-﹏0-9_"; -exports.isBuffer = _dereq_('./support/isBuffer'); +var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]"); +var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]"); -function objectToString(o) { - return Object.prototype.toString.call(o); -} +nonASCIIidentifierStartChars = nonASCIIidentifierChars = null; +// These are a run-length and offset encoded representation of the +// >0xffff code points that are a valid part of identifiers. The +// offset starts at 0x10000, and each pair of numbers represents an +// offset to the next range, and then a size of the range. They were +// generated by tools/generate-identifier-regex.js +var astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 17, 26, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 99, 39, 9, 51, 157, 310, 10, 21, 11, 7, 153, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 98, 21, 11, 25, 71, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 26, 45, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 955, 52, 76, 44, 33, 24, 27, 35, 42, 34, 4, 0, 13, 47, 15, 3, 22, 0, 38, 17, 2, 24, 133, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 32, 4, 287, 47, 21, 1, 2, 0, 185, 46, 82, 47, 21, 0, 60, 42, 502, 63, 32, 0, 449, 56, 1288, 920, 104, 110, 2962, 1070, 13266, 568, 8, 30, 114, 29, 19, 47, 17, 3, 32, 20, 6, 18, 881, 68, 12, 0, 67, 12, 16481, 1, 3071, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 4149, 196, 1340, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42710, 42, 4148, 12, 221, 16355, 541]; +var astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 1306, 2, 54, 14, 32, 9, 16, 3, 46, 10, 54, 9, 7, 2, 37, 13, 2, 9, 52, 0, 13, 2, 49, 13, 16, 9, 83, 11, 168, 11, 6, 9, 8, 2, 57, 0, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 316, 19, 13, 9, 214, 6, 3, 8, 112, 16, 16, 9, 82, 12, 9, 9, 535, 9, 20855, 9, 135, 4, 60, 6, 26, 9, 1016, 45, 17, 3, 19723, 1, 5319, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 4305, 6, 792618, 239]; -function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); +// This has a complexity linear to the value of the code. The +// assumption is that looking up astral identifier characters is +// rare. +function isInAstralSet(code, set) { + var pos = 0x10000; + for (var i = 0; i < set.length; i += 2) { + pos += set[i]; + if (pos > code) return false; + pos += set[i + 1]; + if (pos >= code) return true; + } } +// Test whether a given character code starts an identifier. + +function isIdentifierStart(code, astral) { + if (code < 65) return code === 36; + if (code < 91) return true; + if (code < 97) return code === 95; + if (code < 123) return true; + if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code)); + if (astral === false) return false; + return isInAstralSet(code, astralIdentifierStartCodes); +} -var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; +// Test whether a given character is part of an identifier. -// 26 Feb 16:19:34 -function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); +function isIdentifierChar(code, astral) { + if (code < 48) return code === 36; + if (code < 58) return true; + if (code < 65) return false; + if (code < 91) return true; + if (code < 97) return code === 95; + if (code < 123) return true; + if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code)); + if (astral === false) return false; + return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes); } +},{}],3:[function(_dereq_,module,exports){ +// Acorn is a tiny, fast JavaScript parser written in JavaScript. +// +// Acorn was written by Marijn Haverbeke, Ingvar Stepanyan, and +// various contributors and released under an MIT license. +// +// Git repositories for Acorn are available at +// +// http://marijnhaverbeke.nl/git/acorn +// https://github.com/marijnh/acorn.git +// +// Please use the [github bug tracker][ghbt] to report issues. +// +// [ghbt]: https://github.com/marijnh/acorn/issues +// +// This file defines the main parser interface. The library also comes +// with a [error-tolerant parser][dammit] and an +// [abstract syntax tree walker][walk], defined in other files. +// +// [dammit]: acorn_loose.js +// [walk]: util/walk.js -// log is just a thin wrapper to console.log that prepends a timestamp -exports.log = function() { - console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); -}; +"use strict"; +exports.__esModule = true; +exports.parse = parse; +exports.parseExpressionAt = parseExpressionAt; +exports.tokenizer = tokenizer; -/** - * Inherit the prototype methods from one constructor into another. - * - * The Function.prototype.inherits from lang.js rewritten as a standalone - * function (not on Function.prototype). NOTE: If this file is to be loaded - * during bootstrapping this function needs to be rewritten using some native - * functions as prototype setup using normal JavaScript does not work as - * expected during bootstrapping (see mirror.js in r114903). - * - * @param {function} ctor Constructor function which needs to inherit the - * prototype. - * @param {function} superCtor Constructor function to inherit prototype from. - */ -exports.inherits = _dereq_('inherits'); +var _state = _dereq_("./state"); -exports._extend = function(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; +var _options = _dereq_("./options"); - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; -}; +_dereq_("./parseutil"); -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} +_dereq_("./statement"); -}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./support/isBuffer":4,"_process":3,"inherits":2}],6:[function(_dereq_,module,exports){ -// A recursive descent parser operates by defining functions for all -// syntactic elements, and recursively calling those, each function -// advancing the input stream and returning an AST node. Precedence -// of constructs (for example, the fact that `!x[1]` means `!(x[1])` -// instead of `(!x)[1]` is handled by the fact that the parser -// function that parses unary prefix operators is called first, and -// in turn calls the function that parses `[]` subscripts — that -// way, it'll receive the node for `x[1]` already parsed, and wraps -// *that* in the unary operator node. -// -// Acorn uses an [operator precedence parser][opp] to handle binary -// operator precedence, because it is much more compact than using -// the technique outlined above, which uses different, nesting -// functions to specify precedence, for all of the ten binary -// precedence levels that JavaScript defines. -// -// [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser +_dereq_("./lval"); -"use strict"; +_dereq_("./expression"); -var tt = _dereq_("./tokentype").types; +_dereq_("./location"); -var Parser = _dereq_("./state").Parser; +exports.Parser = _state.Parser; +exports.plugins = _state.plugins; +exports.defaultOptions = _options.defaultOptions; -var reservedWords = _dereq_("./identifier").reservedWords; +var _locutil = _dereq_("./locutil"); -var has = _dereq_("./util").has; +exports.Position = _locutil.Position; +exports.SourceLocation = _locutil.SourceLocation; +exports.getLineInfo = _locutil.getLineInfo; -var pp = Parser.prototype; +var _node = _dereq_("./node"); -// Check if property name clashes with already added. -// Object/class getters and setters are not allowed to clash — -// either with each other or with an init property — and in -// strict mode, init properties are also not allowed to be repeated. +exports.Node = _node.Node; -pp.checkPropClash = function (prop, propHash) { - if (this.options.ecmaVersion >= 6) return; - var key = prop.key, - name = undefined; - switch (key.type) { - case "Identifier": - name = key.name;break; - case "Literal": - name = String(key.value);break; - default: - return; - } - var kind = prop.kind || "init", - other = undefined; - if (has(propHash, name)) { - other = propHash[name]; - var isGetSet = kind !== "init"; - if ((this.strict || isGetSet) && other[kind] || !(isGetSet ^ other.init)) this.raise(key.start, "Redefinition of property"); - } else { - other = propHash[name] = { - init: false, - get: false, - set: false - }; - } - other[kind] = true; -}; +var _tokentype = _dereq_("./tokentype"); -// ### Expression parsing +exports.TokenType = _tokentype.TokenType; +exports.tokTypes = _tokentype.types; -// These nest, from the most general expression type at the top to -// 'atomic', nondivisible expression types at the bottom. Most of -// the functions will simply let the function(s) below them parse, -// and, *if* the syntactic construct they handle is present, wrap -// the AST node that the inner parser gave them in another node. +var _tokencontext = _dereq_("./tokencontext"); -// Parse a full expression. The optional arguments are used to -// forbid the `in` operator (in for loops initalization expressions) -// and provide reference for storing '=' operator inside shorthand -// property assignment in contexts where both object expression -// and object pattern might appear (so it's possible to raise -// delayed syntax error at correct position). +exports.TokContext = _tokencontext.TokContext; +exports.tokContexts = _tokencontext.types; -pp.parseExpression = function (noIn, refShorthandDefaultPos) { - var startPos = this.start, - startLoc = this.startLoc; - var expr = this.parseMaybeAssign(noIn, refShorthandDefaultPos); - if (this.type === tt.comma) { - var node = this.startNodeAt(startPos, startLoc); - node.expressions = [expr]; - while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(noIn, refShorthandDefaultPos)); - return this.finishNode(node, "SequenceExpression"); - } - return expr; -}; +var _identifier = _dereq_("./identifier"); -// Parse an assignment expression. This includes applications of -// operators like `+=`. +exports.isIdentifierChar = _identifier.isIdentifierChar; +exports.isIdentifierStart = _identifier.isIdentifierStart; -pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse) { - if (this.type == tt._yield && this.inGenerator) return this.parseYield(); +var _tokenize = _dereq_("./tokenize"); - var failOnShorthandAssign = undefined; - if (!refShorthandDefaultPos) { - refShorthandDefaultPos = { start: 0 }; - failOnShorthandAssign = true; - } else { - failOnShorthandAssign = false; - } - var startPos = this.start, - startLoc = this.startLoc; - if (this.type == tt.parenL || this.type == tt.name) this.potentialArrowAt = this.start; - var left = this.parseMaybeConditional(noIn, refShorthandDefaultPos); - if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc); - if (this.type.isAssign) { - var node = this.startNodeAt(startPos, startLoc); - node.operator = this.value; - node.left = this.type === tt.eq ? this.toAssignable(left) : left; - refShorthandDefaultPos.start = 0; // reset because shorthand default was used correctly - this.checkLVal(left); - this.next(); - node.right = this.parseMaybeAssign(noIn); - return this.finishNode(node, "AssignmentExpression"); - } else if (failOnShorthandAssign && refShorthandDefaultPos.start) { - this.unexpected(refShorthandDefaultPos.start); - } - return left; -}; +exports.Token = _tokenize.Token; -// Parse a ternary conditional (`?:`) operator. +var _whitespace = _dereq_("./whitespace"); -pp.parseMaybeConditional = function (noIn, refShorthandDefaultPos) { - var startPos = this.start, - startLoc = this.startLoc; - var expr = this.parseExprOps(noIn, refShorthandDefaultPos); - if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; - if (this.eat(tt.question)) { - var node = this.startNodeAt(startPos, startLoc); - node.test = expr; - node.consequent = this.parseMaybeAssign(); - this.expect(tt.colon); - node.alternate = this.parseMaybeAssign(noIn); - return this.finishNode(node, "ConditionalExpression"); - } - return expr; -}; +exports.isNewLine = _whitespace.isNewLine; +exports.lineBreak = _whitespace.lineBreak; +exports.lineBreakG = _whitespace.lineBreakG; +var version = "2.1.0"; -// Start the precedence parser. +exports.version = version; +// The main exported interface (under `self.acorn` when in the +// browser) is a `parse` function that takes a code string and +// returns an abstract syntax tree as specified by [Mozilla parser +// API][api]. +// +// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API -pp.parseExprOps = function (noIn, refShorthandDefaultPos) { - var startPos = this.start, - startLoc = this.startLoc; - var expr = this.parseMaybeUnary(refShorthandDefaultPos); - if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; - return this.parseExprOp(expr, startPos, startLoc, -1, noIn); -}; +function parse(input, options) { + return new _state.Parser(options, input).parse(); +} -// Parse binary operators with the operator precedence parsing -// algorithm. `left` is the left-hand side of the operator. -// `minPrec` provides context that allows the function to stop and -// defer further parser to one of its callers when it encounters an -// operator that has a lower precedence than the set it is parsing. +// This function tries to parse a single expression at a given +// offset in a string. Useful for parsing mixed-language formats +// that embed JavaScript expressions. -pp.parseExprOp = function (left, leftStartPos, leftStartLoc, minPrec, noIn) { - var prec = this.type.binop; - if (Array.isArray(leftStartPos)) { - if (this.options.locations && noIn === undefined) { - // shift arguments to left by one - noIn = minPrec; - minPrec = leftStartLoc; - // flatten leftStartPos - leftStartLoc = leftStartPos[1]; - leftStartPos = leftStartPos[0]; - } - } - if (prec != null && (!noIn || this.type !== tt._in)) { - if (prec > minPrec) { - var node = this.startNodeAt(leftStartPos, leftStartLoc); - node.left = left; - node.operator = this.value; - var op = this.type; - this.next(); - var startPos = this.start, - startLoc = this.startLoc; - node.right = this.parseExprOp(this.parseMaybeUnary(), startPos, startLoc, prec, noIn); - this.finishNode(node, op === tt.logicalOR || op === tt.logicalAND ? "LogicalExpression" : "BinaryExpression"); - return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn); - } - } - return left; -}; +function parseExpressionAt(input, pos, options) { + var p = new _state.Parser(options, input, pos); + p.nextToken(); + return p.parseExpression(); +} -// Parse unary operators, both prefix and postfix. +// Acorn is organized as a tokenizer and a recursive-descent parser. +// The `tokenize` export provides an interface to the tokenizer. -pp.parseMaybeUnary = function (refShorthandDefaultPos) { - if (this.type.prefix) { - var node = this.startNode(), - update = this.type === tt.incDec; - node.operator = this.value; - node.prefix = true; - this.next(); - node.argument = this.parseMaybeUnary(); - if (refShorthandDefaultPos && refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start); - if (update) this.checkLVal(node.argument);else if (this.strict && node.operator === "delete" && node.argument.type === "Identifier") this.raise(node.start, "Deleting local variable in strict mode"); - return this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression"); - } - var startPos = this.start, - startLoc = this.startLoc; - var expr = this.parseExprSubscripts(refShorthandDefaultPos); - if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; - while (this.type.postfix && !this.canInsertSemicolon()) { - var node = this.startNodeAt(startPos, startLoc); - node.operator = this.value; - node.prefix = false; - node.argument = expr; - this.checkLVal(expr); - this.next(); - expr = this.finishNode(node, "UpdateExpression"); - } - return expr; -}; +function tokenizer(input, options) { + return new _state.Parser(options, input); +} -// Parse call, dot, and `[]`-subscript expressions. +},{"./expression":1,"./identifier":2,"./location":4,"./locutil":5,"./lval":6,"./node":7,"./options":8,"./parseutil":9,"./state":10,"./statement":11,"./tokencontext":12,"./tokenize":13,"./tokentype":14,"./whitespace":16}],4:[function(_dereq_,module,exports){ +"use strict"; -pp.parseExprSubscripts = function (refShorthandDefaultPos) { - var startPos = this.start, - startLoc = this.startLoc; - var expr = this.parseExprAtom(refShorthandDefaultPos); - if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; - return this.parseSubscripts(expr, startPos, startLoc); +var _state = _dereq_("./state"); + +var _locutil = _dereq_("./locutil"); + +var pp = _state.Parser.prototype; + +// This function is used to raise exceptions on parse errors. It +// takes an offset integer (into the current `input`) to indicate +// the location of the error, attaches the position to the end +// of the error message, and then raises a `SyntaxError` with that +// message. + +pp.raise = function (pos, message) { + var loc = _locutil.getLineInfo(this.input, pos); + message += " (" + loc.line + ":" + loc.column + ")"; + var err = new SyntaxError(message); + err.pos = pos;err.loc = loc;err.raisedAt = this.pos; + throw err; }; -pp.parseSubscripts = function (base, startPos, startLoc, noCalls) { - if (Array.isArray(startPos)) { - if (this.options.locations && noCalls === undefined) { - // shift arguments to left by one - noCalls = startLoc; - // flatten startPos - startLoc = startPos[1]; - startPos = startPos[0]; - } - } - for (;;) { - if (this.eat(tt.dot)) { - var node = this.startNodeAt(startPos, startLoc); - node.object = base; - node.property = this.parseIdent(true); - node.computed = false; - base = this.finishNode(node, "MemberExpression"); - } else if (this.eat(tt.bracketL)) { - var node = this.startNodeAt(startPos, startLoc); - node.object = base; - node.property = this.parseExpression(); - node.computed = true; - this.expect(tt.bracketR); - base = this.finishNode(node, "MemberExpression"); - } else if (!noCalls && this.eat(tt.parenL)) { - var node = this.startNodeAt(startPos, startLoc); - node.callee = base; - node.arguments = this.parseExprList(tt.parenR, false); - base = this.finishNode(node, "CallExpression"); - } else if (this.type === tt.backQuote) { - var node = this.startNodeAt(startPos, startLoc); - node.tag = base; - node.quasi = this.parseTemplate(); - base = this.finishNode(node, "TaggedTemplateExpression"); - } else { - return base; - } +pp.curPosition = function () { + if (this.options.locations) { + return new _locutil.Position(this.curLine, this.pos - this.lineStart); } }; -// Parse an atomic expression — either a single token that is an -// expression, an expression started by a keyword like `function` or -// `new`, or an expression wrapped in punctuation like `()`, `[]`, -// or `{}`. +},{"./locutil":5,"./state":10}],5:[function(_dereq_,module,exports){ +"use strict"; -pp.parseExprAtom = function (refShorthandDefaultPos) { - var node = undefined, - canBeArrow = this.potentialArrowAt == this.start; - switch (this.type) { - case tt._this: - case tt._super: - var type = this.type === tt._this ? "ThisExpression" : "Super"; - node = this.startNode(); - this.next(); - return this.finishNode(node, type); +exports.__esModule = true; +exports.getLineInfo = getLineInfo; - case tt._yield: - if (this.inGenerator) this.unexpected(); +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - case tt.name: - var startPos = this.start, - startLoc = this.startLoc; - var id = this.parseIdent(this.type !== tt.name); - if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id]); - return id; +var _whitespace = _dereq_("./whitespace"); - case tt.regexp: - var value = this.value; - node = this.parseLiteral(value.value); - node.regex = { pattern: value.pattern, flags: value.flags }; - return node; +// These are used when `options.locations` is on, for the +// `startLoc` and `endLoc` properties. - case tt.num:case tt.string: - return this.parseLiteral(this.value); +var Position = (function () { + function Position(line, col) { + _classCallCheck(this, Position); - case tt._null:case tt._true:case tt._false: - node = this.startNode(); - node.value = this.type === tt._null ? null : this.type === tt._true; - node.raw = this.type.keyword; - this.next(); - return this.finishNode(node, "Literal"); + this.line = line; + this.column = col; + } - case tt.parenL: - return this.parseParenAndDistinguishExpression(canBeArrow); + Position.prototype.offset = function offset(n) { + return new Position(this.line, this.column + n); + }; - case tt.bracketL: - node = this.startNode(); - this.next(); - // check whether this is array comprehension or regular array - if (this.options.ecmaVersion >= 7 && this.type === tt._for) { - return this.parseComprehension(node, false); - } - node.elements = this.parseExprList(tt.bracketR, true, true, refShorthandDefaultPos); - return this.finishNode(node, "ArrayExpression"); + return Position; +})(); - case tt.braceL: - return this.parseObj(false, refShorthandDefaultPos); +exports.Position = Position; - case tt._function: - node = this.startNode(); - this.next(); - return this.parseFunction(node, false); +var SourceLocation = function SourceLocation(p, start, end) { + _classCallCheck(this, SourceLocation); - case tt._class: - return this.parseClass(this.startNode(), false); + this.start = start; + this.end = end; + if (p.sourceFile !== null) this.source = p.sourceFile; +}; - case tt._new: - return this.parseNew(); +exports.SourceLocation = SourceLocation; - case tt.backQuote: - return this.parseTemplate(); +// The `getLineInfo` function is mostly useful when the +// `locations` option is off (for performance reasons) and you +// want to find the line/column position for a given character +// offset. `input` should be the code string that the offset refers +// into. - default: - this.unexpected(); +function getLineInfo(input, offset) { + for (var line = 1, cur = 0;;) { + _whitespace.lineBreakG.lastIndex = cur; + var match = _whitespace.lineBreakG.exec(input); + if (match && match.index < offset) { + ++line; + cur = match.index + match[0].length; + } else { + return new Position(line, offset - cur); + } } -}; +} -pp.parseLiteral = function (value) { - var node = this.startNode(); - node.value = value; - node.raw = this.input.slice(this.start, this.end); - this.next(); - return this.finishNode(node, "Literal"); -}; +},{"./whitespace":16}],6:[function(_dereq_,module,exports){ +"use strict"; -pp.parseParenExpression = function () { - this.expect(tt.parenL); - var val = this.parseExpression(); - this.expect(tt.parenR); - return val; -}; +var _tokentype = _dereq_("./tokentype"); -pp.parseParenAndDistinguishExpression = function (canBeArrow) { - var startPos = this.start, - startLoc = this.startLoc, - val = undefined; - if (this.options.ecmaVersion >= 6) { - this.next(); +var _state = _dereq_("./state"); - if (this.options.ecmaVersion >= 7 && this.type === tt._for) { - return this.parseComprehension(this.startNodeAt(startPos, startLoc), true); - } +var _identifier = _dereq_("./identifier"); - var innerStartPos = this.start, - innerStartLoc = this.startLoc; - var exprList = [], - first = true; - var refShorthandDefaultPos = { start: 0 }, - spreadStart = undefined, - innerParenStart = undefined; - while (this.type !== tt.parenR) { - first ? first = false : this.expect(tt.comma); - if (this.type === tt.ellipsis) { - spreadStart = this.start; - exprList.push(this.parseParenItem(this.parseRest())); - break; - } else { - if (this.type === tt.parenL && !innerParenStart) { - innerParenStart = this.start; - } - exprList.push(this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem)); - } - } - var innerEndPos = this.start, - innerEndLoc = this.startLoc; - this.expect(tt.parenR); +var _util = _dereq_("./util"); - if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) { - if (innerParenStart) this.unexpected(innerParenStart); - return this.parseParenArrowList(startPos, startLoc, exprList); - } +var pp = _state.Parser.prototype; - if (!exprList.length) this.unexpected(this.lastTokStart); - if (spreadStart) this.unexpected(spreadStart); - if (refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start); +// Convert existing expression atom to assignable pattern +// if possible. - if (exprList.length > 1) { - val = this.startNodeAt(innerStartPos, innerStartLoc); - val.expressions = exprList; - this.finishNodeAt(val, "SequenceExpression", innerEndPos, innerEndLoc); - } else { - val = exprList[0]; - } - } else { - val = this.parseParenExpression(); - } +pp.toAssignable = function (node, isBinding) { + if (this.options.ecmaVersion >= 6 && node) { + switch (node.type) { + case "Identifier": + case "ObjectPattern": + case "ArrayPattern": + case "AssignmentPattern": + break; - if (this.options.preserveParens) { - var par = this.startNodeAt(startPos, startLoc); - par.expression = val; - return this.finishNode(par, "ParenthesizedExpression"); - } else { - return val; - } -}; + case "ObjectExpression": + node.type = "ObjectPattern"; + for (var i = 0; i < node.properties.length; i++) { + var prop = node.properties[i]; + if (prop.kind !== "init") this.raise(prop.key.start, "Object pattern can't contain getter or setter"); + this.toAssignable(prop.value, isBinding); + } + break; -pp.parseParenItem = function (item) { - return item; -}; + case "ArrayExpression": + node.type = "ArrayPattern"; + this.toAssignableList(node.elements, isBinding); + break; -pp.parseParenArrowList = function (startPos, startLoc, exprList) { - return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList); -}; + case "AssignmentExpression": + if (node.operator === "=") { + node.type = "AssignmentPattern"; + delete node.operator; + } else { + this.raise(node.left.end, "Only '=' operator can be used for specifying default value."); + } + break; -// New's precedence is slightly tricky. It must allow its argument -// to be a `[]` or dot subscript expression, but not a call — at -// least, not without wrapping it in parentheses. Thus, it uses the + case "ParenthesizedExpression": + node.expression = this.toAssignable(node.expression, isBinding); + break; -var empty = []; + case "MemberExpression": + if (!isBinding) break; -pp.parseNew = function () { - var node = this.startNode(); - var meta = this.parseIdent(true); - if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) { - node.meta = meta; - node.property = this.parseIdent(true); - if (node.property.name !== "target") this.raise(node.property.start, "The only valid meta property for new is new.target"); - return this.finishNode(node, "MetaProperty"); + default: + this.raise(node.start, "Assigning to rvalue"); + } } - var startPos = this.start, - startLoc = this.startLoc; - node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true); - if (this.eat(tt.parenL)) node.arguments = this.parseExprList(tt.parenR, false);else node.arguments = empty; - return this.finishNode(node, "NewExpression"); + return node; }; -// Parse template expression. +// Convert list of expression atoms to binding list. -pp.parseTemplateElement = function () { - var elem = this.startNode(); - elem.value = { - raw: this.input.slice(this.start, this.end), - cooked: this.value - }; - this.next(); - elem.tail = this.type === tt.backQuote; - return this.finishNode(elem, "TemplateElement"); +pp.toAssignableList = function (exprList, isBinding) { + var end = exprList.length; + if (end) { + var last = exprList[end - 1]; + if (last && last.type == "RestElement") { + --end; + } else if (last && last.type == "SpreadElement") { + last.type = "RestElement"; + var arg = last.argument; + this.toAssignable(arg, isBinding); + if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern") this.unexpected(arg.start); + --end; + } + } + for (var i = 0; i < end; i++) { + var elt = exprList[i]; + if (elt) this.toAssignable(elt, isBinding); + } + return exprList; }; -pp.parseTemplate = function () { +// Parses spread element. + +pp.parseSpread = function (refShorthandDefaultPos) { var node = this.startNode(); this.next(); - node.expressions = []; - var curElt = this.parseTemplateElement(); - node.quasis = [curElt]; - while (!curElt.tail) { - this.expect(tt.dollarBraceL); - node.expressions.push(this.parseExpression()); - this.expect(tt.braceR); - node.quasis.push(curElt = this.parseTemplateElement()); - } + node.argument = this.parseMaybeAssign(refShorthandDefaultPos); + return this.finishNode(node, "SpreadElement"); +}; + +pp.parseRest = function () { + var node = this.startNode(); this.next(); - return this.finishNode(node, "TemplateLiteral"); + node.argument = this.type === _tokentype.types.name || this.type === _tokentype.types.bracketL ? this.parseBindingAtom() : this.unexpected(); + return this.finishNode(node, "RestElement"); }; -// Parse an object literal or binding pattern. +// Parses lvalue (assignable) atom. -pp.parseObj = function (isPattern, refShorthandDefaultPos) { - var node = this.startNode(), - first = true, - propHash = {}; - node.properties = []; - this.next(); - while (!this.eat(tt.braceR)) { - if (!first) { - this.expect(tt.comma); - if (this.afterTrailingComma(tt.braceR)) break; - } else first = false; +pp.parseBindingAtom = function () { + if (this.options.ecmaVersion < 6) return this.parseIdent(); + switch (this.type) { + case _tokentype.types.name: + return this.parseIdent(); - var prop = this.startNode(), - isGenerator = undefined, - startPos = undefined, - startLoc = undefined; - if (this.options.ecmaVersion >= 6) { - prop.method = false; - prop.shorthand = false; - if (isPattern || refShorthandDefaultPos) { - startPos = this.start; - startLoc = this.startLoc; - } - if (!isPattern) isGenerator = this.eat(tt.star); - } - this.parsePropertyName(prop); - this.parsePropertyValue(prop, isPattern, isGenerator, startPos, startLoc, refShorthandDefaultPos); - this.checkPropClash(prop, propHash); - node.properties.push(this.finishNode(prop, "Property")); - } - return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression"); -}; + case _tokentype.types.bracketL: + var node = this.startNode(); + this.next(); + node.elements = this.parseBindingList(_tokentype.types.bracketR, true, true); + return this.finishNode(node, "ArrayPattern"); -pp.parsePropertyValue = function (prop, isPattern, isGenerator, startPos, startLoc, refShorthandDefaultPos) { - if (this.eat(tt.colon)) { - prop.value = isPattern ? this.parseMaybeDefault(this.start, this.startLoc) : this.parseMaybeAssign(false, refShorthandDefaultPos); - prop.kind = "init"; - } else if (this.options.ecmaVersion >= 6 && this.type === tt.parenL) { - if (isPattern) this.unexpected(); - prop.kind = "init"; - prop.method = true; - prop.value = this.parseMethod(isGenerator); - } else if (this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" && (prop.key.name === "get" || prop.key.name === "set") && (this.type != tt.comma && this.type != tt.braceR)) { - if (isGenerator || isPattern) this.unexpected(); - prop.kind = prop.key.name; - this.parsePropertyName(prop); - prop.value = this.parseMethod(false); - } else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") { - prop.kind = "init"; - if (isPattern) { - if (this.isKeyword(prop.key.name) || this.strict && (reservedWords.strictBind(prop.key.name) || reservedWords.strict(prop.key.name)) || !this.options.allowReserved && this.isReservedWord(prop.key.name)) this.raise(prop.key.start, "Binding " + prop.key.name); - prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key); - } else if (this.type === tt.eq && refShorthandDefaultPos) { - if (!refShorthandDefaultPos.start) refShorthandDefaultPos.start = this.start; - prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key); - } else { - prop.value = prop.key; - } - prop.shorthand = true; - } else this.unexpected(); + case _tokentype.types.braceL: + return this.parseObj(true); + + default: + this.unexpected(); + } }; -pp.parsePropertyName = function (prop) { - if (this.options.ecmaVersion >= 6) { - if (this.eat(tt.bracketL)) { - prop.computed = true; - prop.key = this.parseMaybeAssign(); - this.expect(tt.bracketR); - return prop.key; +pp.parseBindingList = function (close, allowEmpty, allowTrailingComma) { + var elts = [], + first = true; + while (!this.eat(close)) { + if (first) first = false;else this.expect(_tokentype.types.comma); + if (allowEmpty && this.type === _tokentype.types.comma) { + elts.push(null); + } else if (allowTrailingComma && this.afterTrailingComma(close)) { + break; + } else if (this.type === _tokentype.types.ellipsis) { + var rest = this.parseRest(); + this.parseBindingListItem(rest); + elts.push(rest); + this.expect(close); + break; } else { - prop.computed = false; + var elem = this.parseMaybeDefault(this.start, this.startLoc); + this.parseBindingListItem(elem); + elts.push(elem); } } - return prop.key = this.type === tt.num || this.type === tt.string ? this.parseExprAtom() : this.parseIdent(true); + return elts; }; -// Initialize empty function node. - -pp.initFunction = function (node) { - node.id = null; - if (this.options.ecmaVersion >= 6) { - node.generator = false; - node.expression = false; - } +pp.parseBindingListItem = function (param) { + return param; }; -// Parse object or class method. +// Parses assignment pattern around given atom if possible. -pp.parseMethod = function (isGenerator) { - var node = this.startNode(); - this.initFunction(node); - this.expect(tt.parenL); - node.params = this.parseBindingList(tt.parenR, false, false); - var allowExpressionBody = undefined; - if (this.options.ecmaVersion >= 6) { - node.generator = isGenerator; - allowExpressionBody = true; - } else { - allowExpressionBody = false; - } - this.parseFunctionBody(node, allowExpressionBody); - return this.finishNode(node, "FunctionExpression"); +pp.parseMaybeDefault = function (startPos, startLoc, left) { + left = left || this.parseBindingAtom(); + if (!this.eat(_tokentype.types.eq)) return left; + var node = this.startNodeAt(startPos, startLoc); + node.operator = "="; + node.left = left; + node.right = this.parseMaybeAssign(); + return this.finishNode(node, "AssignmentPattern"); }; -// Parse arrow function expression with given parameters. +// Verify that a node is an lval — something that can be assigned +// to. -pp.parseArrowExpression = function (node, params) { - this.initFunction(node); - node.params = this.toAssignableList(params, true); - this.parseFunctionBody(node, true); - return this.finishNode(node, "ArrowFunctionExpression"); -}; - -// Parse function body and check parameters. - -pp.parseFunctionBody = function (node, allowExpression) { - var isExpression = allowExpression && this.type !== tt.braceL; - - if (isExpression) { - node.body = this.parseMaybeAssign(); - node.expression = true; - } else { - // Start a new scope with regard to labels and the `inFunction` - // flag (restore them to their old value afterwards). - var oldInFunc = this.inFunction, - oldInGen = this.inGenerator, - oldLabels = this.labels; - this.inFunction = true;this.inGenerator = node.generator;this.labels = []; - node.body = this.parseBlock(true); - node.expression = false; - this.inFunction = oldInFunc;this.inGenerator = oldInGen;this.labels = oldLabels; - } - - // If this is a strict mode function, verify that argument names - // are not repeated, and it does not try to bind the words `eval` - // or `arguments`. - if (this.strict || !isExpression && node.body.body.length && this.isUseStrict(node.body.body[0])) { - var nameHash = {}, - oldStrict = this.strict; - this.strict = true; - if (node.id) this.checkLVal(node.id, true); - for (var i = 0; i < node.params.length; i++) { - this.checkLVal(node.params[i], true, nameHash); - }this.strict = oldStrict; - } -}; +pp.checkLVal = function (expr, isBinding, checkClashes) { + switch (expr.type) { + case "Identifier": + if (this.strict && (_identifier.reservedWords.strictBind(expr.name) || _identifier.reservedWords.strict(expr.name))) this.raise(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode"); + if (checkClashes) { + if (_util.has(checkClashes, expr.name)) this.raise(expr.start, "Argument name clash in strict mode"); + checkClashes[expr.name] = true; + } + break; -// Parses a comma-separated list of expressions, and returns them as -// an array. `close` is the token type that ends the list, and -// `allowEmpty` can be turned on to allow subsequent commas with -// nothing in between them to be parsed as `null` (which is needed -// for array literals). + case "MemberExpression": + if (isBinding) this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression"); + break; -pp.parseExprList = function (close, allowTrailingComma, allowEmpty, refShorthandDefaultPos) { - var elts = [], - first = true; - while (!this.eat(close)) { - if (!first) { - this.expect(tt.comma); - if (allowTrailingComma && this.afterTrailingComma(close)) break; - } else first = false; + case "ObjectPattern": + for (var i = 0; i < expr.properties.length; i++) { + this.checkLVal(expr.properties[i].value, isBinding, checkClashes); + }break; - if (allowEmpty && this.type === tt.comma) { - elts.push(null); - } else { - if (this.type === tt.ellipsis) elts.push(this.parseSpread(refShorthandDefaultPos));else elts.push(this.parseMaybeAssign(false, refShorthandDefaultPos)); - } - } - return elts; -}; + case "ArrayPattern": + for (var i = 0; i < expr.elements.length; i++) { + var elem = expr.elements[i]; + if (elem) this.checkLVal(elem, isBinding, checkClashes); + } + break; -// Parse the next token as an identifier. If `liberal` is true (used -// when parsing properties), it will also convert keywords into -// identifiers. + case "AssignmentPattern": + this.checkLVal(expr.left, isBinding, checkClashes); + break; -pp.parseIdent = function (liberal) { - var node = this.startNode(); - if (liberal && this.options.allowReserved == "never") liberal = false; - if (this.type === tt.name) { - if (!liberal && (!this.options.allowReserved && this.isReservedWord(this.value) || this.strict && reservedWords.strict(this.value) && (this.options.ecmaVersion >= 6 || this.input.slice(this.start, this.end).indexOf("\\") == -1))) this.raise(this.start, "The keyword '" + this.value + "' is reserved"); - node.name = this.value; - } else if (liberal && this.type.keyword) { - node.name = this.type.keyword; - } else { - this.unexpected(); - } - this.next(); - return this.finishNode(node, "Identifier"); -}; + case "RestElement": + this.checkLVal(expr.argument, isBinding, checkClashes); + break; -// Parses yield expression inside generator. + case "ParenthesizedExpression": + this.checkLVal(expr.expression, isBinding, checkClashes); + break; -pp.parseYield = function () { - var node = this.startNode(); - this.next(); - if (this.type == tt.semi || this.canInsertSemicolon() || this.type != tt.star && !this.type.startsExpr) { - node.delegate = false; - node.argument = null; - } else { - node.delegate = this.eat(tt.star); - node.argument = this.parseMaybeAssign(); + default: + this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue"); } - return this.finishNode(node, "YieldExpression"); }; -// Parses array and generator comprehensions. +},{"./identifier":2,"./state":10,"./tokentype":14,"./util":15}],7:[function(_dereq_,module,exports){ +"use strict"; -pp.parseComprehension = function (node, isGenerator) { - node.blocks = []; - while (this.type === tt._for) { - var block = this.startNode(); - this.next(); - this.expect(tt.parenL); - block.left = this.parseBindingAtom(); - this.checkLVal(block.left, true); - this.expectContextual("of"); - block.right = this.parseExpression(); - this.expect(tt.parenR); - node.blocks.push(this.finishNode(block, "ComprehensionBlock")); - } - node.filter = this.eat(tt._if) ? this.parseParenExpression() : null; - node.body = this.parseExpression(); - this.expect(isGenerator ? tt.parenR : tt.bracketR); - node.generator = isGenerator; - return this.finishNode(node, "ComprehensionExpression"); -}; +exports.__esModule = true; -},{"./identifier":7,"./state":13,"./tokentype":17,"./util":18}],7:[function(_dereq_,module,exports){ +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +var _state = _dereq_("./state"); -// Test whether a given character code starts an identifier. +var _locutil = _dereq_("./locutil"); -"use strict"; +var Node = function Node(parser, pos, loc) { + _classCallCheck(this, Node); -exports.isIdentifierStart = isIdentifierStart; + this.type = ""; + this.start = pos; + this.end = 0; + if (parser.options.locations) this.loc = new _locutil.SourceLocation(parser, loc); + if (parser.options.directSourceFile) this.sourceFile = parser.options.directSourceFile; + if (parser.options.ranges) this.range = [pos, 0]; +}; -// Test whether a given character is part of an identifier. +exports.Node = Node; -exports.isIdentifierChar = isIdentifierChar; -exports.__esModule = true; -// This is a trick taken from Esprima. It turns out that, on -// non-Chrome browsers, to check whether a string is in a set, a -// predicate containing a big ugly `switch` statement is faster than -// a regular expression, and on Chrome the two are about on par. -// This function uses `eval` (non-lexical) to produce such a -// predicate from a space-separated string of words. -// -// It starts by sorting the words by length. +// Start an AST node, attaching a start offset. -function makePredicate(words) { - words = words.split(" "); - var f = "", - cats = []; - out: for (var i = 0; i < words.length; ++i) { - for (var j = 0; j < cats.length; ++j) { - if (cats[j][0].length == words[i].length) { - cats[j].push(words[i]); - continue out; - } - }cats.push([words[i]]); - } - function compareTo(arr) { - if (arr.length == 1) { - return f += "return str === " + JSON.stringify(arr[0]) + ";"; - }f += "switch(str){"; - for (var i = 0; i < arr.length; ++i) { - f += "case " + JSON.stringify(arr[i]) + ":"; - }f += "return true}return false;"; - } +var pp = _state.Parser.prototype; - // When there are more than three length categories, an outer - // switch first dispatches on the lengths, to save on comparisons. +pp.startNode = function () { + return new Node(this, this.start, this.startLoc); +}; - if (cats.length > 3) { - cats.sort(function (a, b) { - return b.length - a.length; - }); - f += "switch(str.length){"; - for (var i = 0; i < cats.length; ++i) { - var cat = cats[i]; - f += "case " + cat[0].length + ":"; - compareTo(cat); - } - f += "}" +pp.startNodeAt = function (pos, loc) { + return new Node(this, pos, loc); +}; - // Otherwise, simply generate a flat `switch` statement. +// Finish an AST node, adding `type` and `end` properties. - ; - } else { - compareTo(words); - } - return new Function("str", f); +function finishNodeAt(node, type, pos, loc) { + node.type = type; + node.end = pos; + if (this.options.locations) node.loc.end = loc; + if (this.options.ranges) node.range[1] = pos; + return node; } -// Reserved word lists for various dialects of the language - -var reservedWords = { - 3: makePredicate("abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile"), - 5: makePredicate("class enum extends super const export import"), - 6: makePredicate("enum await"), - strict: makePredicate("implements interface let package private protected public static yield"), - strictBind: makePredicate("eval arguments") +pp.finishNode = function (node, type) { + return finishNodeAt.call(this, node, type, this.lastTokEnd, this.lastTokEndLoc); }; -exports.reservedWords = reservedWords; -// And the keywords - -var ecma5AndLessKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this"; +// Finish node at given position -var keywords = { - 5: makePredicate(ecma5AndLessKeywords), - 6: makePredicate(ecma5AndLessKeywords + " let const class extends export import yield super") +pp.finishNodeAt = function (node, type, pos, loc) { + return finishNodeAt.call(this, node, type, pos, loc); }; -exports.keywords = keywords; -// ## Character categories - -// Big ugly regular expressions that match characters in the -// whitespace, identifier, and identifier-start categories. These -// are only applied when a character is found to actually have a -// code point above 128. -// Generated by `tools/generate-identifier-regex.js`. - -var nonASCIIidentifierStartChars = "ªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽͿΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠ-ࢲऄ-हऽॐक़-ॡॱ-ঀঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-హఽౘౙౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൠൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛮ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᧁ-ᧇᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕ℘-ℝℤΩℨK-ℹℼ-ℿⅅ-ⅉⅎⅠ-ↈⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞ々-〇〡-〩〱-〵〸-〼ぁ-ゖ゛-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚝꚠ-ꛯꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞭꞰꞱꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꩾ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭟꭤꭥꯀ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ"; -var nonASCIIidentifierChars = "‌‍·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-٩ٰۖ-ۜ۟-۪ۤۧۨ-ۭ۰-۹ܑܰ-݊ަ-ް߀-߉߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣤ-ःऺ-़ा-ॏ॑-ॗॢॣ०-९ঁ-ঃ়া-ৄেৈো-্ৗৢৣ০-৯ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑ੦-ੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣ૦-૯ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣ୦-୯ஂா-ூெ-ைொ-்ௗ௦-௯ఀ-ఃా-ౄె-ైొ-్ౕౖౢౣ౦-౯ಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣ೦-೯ഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣ൦-൯ංඃ්ා-ුූෘ-ෟ෦-෯ෲෳัิ-ฺ็-๎๐-๙ັິ-ູົຼ່-ໍ໐-໙༘༙༠-༩༹༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှ၀-၉ၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏ-ႝ፝-፟፩-፱ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝០-៩᠋-᠍᠐-᠙ᢩᤠ-ᤫᤰ-᤻᥆-᥏ᦰ-ᧀᧈᧉ᧐-᧚ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼-᪉᪐-᪙᪰-᪽ᬀ-ᬄ᬴-᭄᭐-᭙᭫-᭳ᮀ-ᮂᮡ-ᮭ᮰-᮹᯦-᯳ᰤ-᰷᱀-᱉᱐-᱙᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷼-᷿‿⁀⁔⃐-⃥⃜⃡-⃰⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꘠-꘩꙯ꙴ-꙽ꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-꣄꣐-꣙꣠-꣱꤀-꤉ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀꧐-꧙ꧥ꧰-꧹ꨩ-ꨶꩃꩌꩍ꩐-꩙ꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭꯰-꯹ﬞ︀-️︠-︭︳︴﹍-﹏0-9_"; +},{"./locutil":5,"./state":10}],8:[function(_dereq_,module,exports){ +"use strict"; -var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]"); -var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]"); +exports.__esModule = true; +exports.getOptions = getOptions; -nonASCIIidentifierStartChars = nonASCIIidentifierChars = null; +var _util = _dereq_("./util"); -// These are a run-length and offset encoded representation of the -// >0xffff code points that are a valid part of identifiers. The -// offset starts at 0x10000, and each pair of numbers represents an -// offset to the next range, and then a size of the range. They were -// generated by tools/generate-identifier-regex.js -var astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 17, 26, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 99, 39, 9, 51, 157, 310, 10, 21, 11, 7, 153, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 98, 21, 11, 25, 71, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 26, 45, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 955, 52, 76, 44, 33, 24, 27, 35, 42, 34, 4, 0, 13, 47, 15, 3, 22, 0, 38, 17, 2, 24, 133, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 32, 4, 287, 47, 21, 1, 2, 0, 185, 46, 82, 47, 21, 0, 60, 42, 502, 63, 32, 0, 449, 56, 1288, 920, 104, 110, 2962, 1070, 13266, 568, 8, 30, 114, 29, 19, 47, 17, 3, 32, 20, 6, 18, 881, 68, 12, 0, 67, 12, 16481, 1, 3071, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 4149, 196, 1340, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42710, 42, 4148, 12, 221, 16355, 541]; -var astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 1306, 2, 54, 14, 32, 9, 16, 3, 46, 10, 54, 9, 7, 2, 37, 13, 2, 9, 52, 0, 13, 2, 49, 13, 16, 9, 83, 11, 168, 11, 6, 9, 8, 2, 57, 0, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 316, 19, 13, 9, 214, 6, 3, 8, 112, 16, 16, 9, 82, 12, 9, 9, 535, 9, 20855, 9, 135, 4, 60, 6, 26, 9, 1016, 45, 17, 3, 19723, 1, 5319, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 4305, 6, 792618, 239]; +var _locutil = _dereq_("./locutil"); -// This has a complexity linear to the value of the code. The -// assumption is that looking up astral identifier characters is -// rare. -function isInAstralSet(code, set) { - var pos = 65536; - for (var i = 0; i < set.length; i += 2) { - pos += set[i]; - if (pos > code) { - return false; - }pos += set[i + 1]; - if (pos >= code) { - return true; - } - } -} -function isIdentifierStart(code, astral) { - if (code < 65) { - return code === 36; - }if (code < 91) { - return true; - }if (code < 97) { - return code === 95; - }if (code < 123) { - return true; - }if (code <= 65535) { - return code >= 170 && nonASCIIidentifierStart.test(String.fromCharCode(code)); - }if (astral === false) { - return false; - }return isInAstralSet(code, astralIdentifierStartCodes); -} +// A second optional argument can be given to further configure +// the parser process. These options are recognized: -function isIdentifierChar(code, astral) { - if (code < 48) { - return code === 36; - }if (code < 58) { - return true; - }if (code < 65) { - return false; - }if (code < 91) { - return true; - }if (code < 97) { - return code === 95; - }if (code < 123) { - return true; - }if (code <= 65535) { - return code >= 170 && nonASCIIidentifier.test(String.fromCharCode(code)); - }if (astral === false) { - return false; - }return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes); -} +var defaultOptions = { + // `ecmaVersion` indicates the ECMAScript version to parse. Must + // be either 3, or 5, or 6. This influences support for strict + // mode, the set of reserved words, support for getters and + // setters and other features. + ecmaVersion: 5, + // Source type ("script" or "module") for different semantics + sourceType: "script", + // `onInsertedSemicolon` can be a callback that will be called + // when a semicolon is automatically inserted. It will be passed + // th position of the comma as an offset, and if `locations` is + // enabled, it is given the location as a `{line, column}` object + // as second argument. + onInsertedSemicolon: null, + // `onTrailingComma` is similar to `onInsertedSemicolon`, but for + // trailing commas. + onTrailingComma: null, + // By default, reserved words are not enforced. Disable + // `allowReserved` to enforce them. When this option has the + // value "never", reserved words and keywords can also not be + // used as property names. + allowReserved: true, + // When enabled, a return at the top level is not considered an + // error. + allowReturnOutsideFunction: false, + // When enabled, import/export statements are not constrained to + // appearing at the top of the program. + allowImportExportEverywhere: false, + // When enabled, hashbang directive in the beginning of file + // is allowed and treated as a line comment. + allowHashBang: false, + // When `locations` is on, `loc` properties holding objects with + // `start` and `end` properties in `{line, column}` form (with + // line being 1-based and column 0-based) will be attached to the + // nodes. + locations: false, + // A function can be passed as `onToken` option, which will + // cause Acorn to call that function with object in the same + // format as tokenize() returns. Note that you are not + // allowed to call the parser from the callback—that will + // corrupt its internal state. + onToken: null, + // A function can be passed as `onComment` option, which will + // cause Acorn to call that function with `(block, text, start, + // end)` parameters whenever a comment is skipped. `block` is a + // boolean indicating whether this is a block (`/* */`) comment, + // `text` is the content of the comment, and `start` and `end` are + // character offsets that denote the start and end of the comment. + // When the `locations` option is on, two more parameters are + // passed, the full `{line, column}` locations of the start and + // end of the comments. Note that you are not allowed to call the + // parser from the callback—that will corrupt its internal state. + onComment: null, + // Nodes have their start and end characters offsets recorded in + // `start` and `end` properties (directly on the node, rather than + // the `loc` object, which holds line/column data. To also add a + // [semi-standardized][range] `range` property holding a `[start, + // end]` array with the same numbers, set the `ranges` option to + // `true`. + // + // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678 + ranges: false, + // It is possible to parse multiple files into a single AST by + // passing the tree produced by parsing the first file as + // `program` option in subsequent parses. This will add the + // toplevel forms of the parsed file to the `Program` (top) node + // of an existing parse tree. + program: null, + // When `locations` is on, you can pass this to record the source + // file in every node's `loc` object. + sourceFile: null, + // This value, if given, is stored in every node, whether + // `locations` is on or off. + directSourceFile: null, + // When enabled, parenthesized expressions are represented by + // (non-standard) ParenthesizedExpression nodes + preserveParens: false, + plugins: {} +}; + +exports.defaultOptions = defaultOptions; +// Interpret and default an options object + +function getOptions(opts) { + var options = {}; + for (var opt in defaultOptions) { + options[opt] = opts && _util.has(opts, opt) ? opts[opt] : defaultOptions[opt]; + }if (_util.isArray(options.onToken)) { + (function () { + var tokens = options.onToken; + options.onToken = function (token) { + return tokens.push(token); + }; + })(); + } + if (_util.isArray(options.onComment)) options.onComment = pushComment(options, options.onComment); + + return options; +} + +function pushComment(options, array) { + return function (block, text, start, end, startLoc, endLoc) { + var comment = { + type: block ? "Block" : "Line", + value: text, + start: start, + end: end + }; + if (options.locations) comment.loc = new _locutil.SourceLocation(this, startLoc, endLoc); + if (options.ranges) comment.range = [start, end]; + array.push(comment); + }; +} -},{}],8:[function(_dereq_,module,exports){ +},{"./locutil":5,"./util":15}],9:[function(_dereq_,module,exports){ "use strict"; -var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; +var _tokentype = _dereq_("./tokentype"); -// The `getLineInfo` function is mostly useful when the -// `locations` option is off (for performance reasons) and you -// want to find the line/column position for a given character -// offset. `input` should be the code string that the offset refers -// into. +var _state = _dereq_("./state"); -exports.getLineInfo = getLineInfo; -exports.__esModule = true; +var _whitespace = _dereq_("./whitespace"); -var Parser = _dereq_("./state").Parser; +var pp = _state.Parser.prototype; -var lineBreakG = _dereq_("./whitespace").lineBreakG; +// ## Parser utilities -var deprecate = _dereq_("util").deprecate; +// Test whether a statement node is the string literal `"use strict"`. -// These are used when `options.locations` is on, for the -// `startLoc` and `endLoc` properties. +pp.isUseStrict = function (stmt) { + return this.options.ecmaVersion >= 5 && stmt.type === "ExpressionStatement" && stmt.expression.type === "Literal" && stmt.expression.raw.slice(1, -1) === "use strict"; +}; -var Position = exports.Position = (function () { - function Position(line, col) { - _classCallCheck(this, Position); +// Predicate that tests whether the next token is of the given +// type, and if yes, consumes it as a side effect. - this.line = line; - this.column = col; +pp.eat = function (type) { + if (this.type === type) { + this.next(); + return true; + } else { + return false; } +}; - Position.prototype.offset = function offset(n) { - return new Position(this.line, this.column + n); - }; +// Tests whether parsed token is a contextual keyword. - return Position; -})(); +pp.isContextual = function (name) { + return this.type === _tokentype.types.name && this.value === name; +}; -var SourceLocation = exports.SourceLocation = function SourceLocation(p, start, end) { - _classCallCheck(this, SourceLocation); +// Consumes contextual keyword if possible. - this.start = start; - this.end = end; - if (p.sourceFile !== null) this.source = p.sourceFile; +pp.eatContextual = function (name) { + return this.value === name && this.eat(_tokentype.types.name); }; -function getLineInfo(input, offset) { - for (var line = 1, cur = 0;;) { - lineBreakG.lastIndex = cur; - var match = lineBreakG.exec(input); - if (match && match.index < offset) { - ++line; - cur = match.index + match[0].length; - } else { - return new Position(line, offset - cur); - } +// Asserts that following token is given contextual keyword. + +pp.expectContextual = function (name) { + if (!this.eatContextual(name)) this.unexpected(); +}; + +// Test whether a semicolon can be inserted at the current position. + +pp.canInsertSemicolon = function () { + return this.type === _tokentype.types.eof || this.type === _tokentype.types.braceR || _whitespace.lineBreak.test(this.input.slice(this.lastTokEnd, this.start)); +}; + +pp.insertSemicolon = function () { + if (this.canInsertSemicolon()) { + if (this.options.onInsertedSemicolon) this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc); + return true; } -} +}; -var pp = Parser.prototype; +// Consume a semicolon, or, failing that, see if we are allowed to +// pretend that there is a semicolon at this position. -// This function is used to raise exceptions on parse errors. It -// takes an offset integer (into the current `input`) to indicate -// the location of the error, attaches the position to the end -// of the error message, and then raises a `SyntaxError` with that -// message. +pp.semicolon = function () { + if (!this.eat(_tokentype.types.semi) && !this.insertSemicolon()) this.unexpected(); +}; -pp.raise = function (pos, message) { - var loc = getLineInfo(this.input, pos); - message += " (" + loc.line + ":" + loc.column + ")"; - var err = new SyntaxError(message); - err.pos = pos;err.loc = loc;err.raisedAt = this.pos; - throw err; +pp.afterTrailingComma = function (tokType) { + if (this.type == tokType) { + if (this.options.onTrailingComma) this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc); + this.next(); + return true; + } }; -pp.curPosition = function () { - return new Position(this.curLine, this.pos - this.lineStart); +// Expect a token of a given type. If found, consume it, otherwise, +// raise an unexpected token error. + +pp.expect = function (type) { + this.eat(type) || this.unexpected(); }; -pp.markPosition = function () { - return this.options.locations ? [this.start, this.startLoc] : this.start; +// Raise an unexpected token error. + +pp.unexpected = function (pos) { + this.raise(pos != null ? pos : this.start, "Unexpected token"); }; -},{"./state":13,"./whitespace":19,"util":5}],9:[function(_dereq_,module,exports){ +},{"./state":10,"./tokentype":14,"./whitespace":16}],10:[function(_dereq_,module,exports){ "use strict"; -var tt = _dereq_("./tokentype").types; +exports.__esModule = true; -var Parser = _dereq_("./state").Parser; +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -var reservedWords = _dereq_("./identifier").reservedWords; +var _identifier = _dereq_("./identifier"); -var has = _dereq_("./util").has; +var _tokentype = _dereq_("./tokentype"); -var pp = Parser.prototype; +var _whitespace = _dereq_("./whitespace"); -// Convert existing expression atom to assignable pattern -// if possible. +var _options = _dereq_("./options"); -pp.toAssignable = function (node, isBinding) { - if (this.options.ecmaVersion >= 6 && node) { - switch (node.type) { - case "Identifier": - case "ObjectPattern": - case "ArrayPattern": - case "AssignmentPattern": - break; +// Registered plugins +var plugins = {}; - case "ObjectExpression": - node.type = "ObjectPattern"; - for (var i = 0; i < node.properties.length; i++) { - var prop = node.properties[i]; - if (prop.kind !== "init") this.raise(prop.key.start, "Object pattern can't contain getter or setter"); - this.toAssignable(prop.value, isBinding); - } - break; +exports.plugins = plugins; - case "ArrayExpression": - node.type = "ArrayPattern"; - this.toAssignableList(node.elements, isBinding); - break; +var Parser = (function () { + function Parser(options, input, startPos) { + _classCallCheck(this, Parser); - case "AssignmentExpression": - if (node.operator === "=") { - node.type = "AssignmentPattern"; - } else { - this.raise(node.left.end, "Only '=' operator can be used for specifying default value."); - } - break; + this.options = _options.getOptions(options); + this.sourceFile = this.options.sourceFile; + this.isKeyword = _identifier.keywords[this.options.ecmaVersion >= 6 ? 6 : 5]; + this.isReservedWord = _identifier.reservedWords[this.options.ecmaVersion]; + this.input = String(input); - case "ParenthesizedExpression": - node.expression = this.toAssignable(node.expression, isBinding); - break; + // Load plugins + this.loadPlugins(this.options.plugins); - case "MemberExpression": - if (!isBinding) break; + // Set up token state - default: - this.raise(node.start, "Assigning to rvalue"); + // The current position of the tokenizer in the input. + if (startPos) { + this.pos = startPos; + this.lineStart = Math.max(0, this.input.lastIndexOf("\n", startPos)); + this.curLine = this.input.slice(0, this.lineStart).split(_whitespace.lineBreak).length; + } else { + this.pos = this.lineStart = 0; + this.curLine = 1; } - } - return node; -}; -// Convert list of expression atoms to binding list. + // Properties of the current token: + // Its type + this.type = _tokentype.types.eof; + // For tokens that include more information than their type, the value + this.value = null; + // Its start and end offset + this.start = this.end = this.pos; + // And, if locations are used, the {line, column} object + // corresponding to those offsets + this.startLoc = this.endLoc = this.curPosition(); + + // Position information for the previous token + this.lastTokEndLoc = this.lastTokStartLoc = null; + this.lastTokStart = this.lastTokEnd = this.pos; + + // The context stack is used to superficially track syntactic + // context to predict whether a regular expression is allowed in a + // given position. + this.context = this.initialContext(); + this.exprAllowed = true; -pp.toAssignableList = function (exprList, isBinding) { - var end = exprList.length; - if (end) { - var last = exprList[end - 1]; - if (last && last.type == "RestElement") { - --end; - } else if (last && last.type == "SpreadElement") { - last.type = "RestElement"; - var arg = last.argument; - this.toAssignable(arg, isBinding); - if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern") this.unexpected(arg.start); - --end; - } - } - for (var i = 0; i < end; i++) { - var elt = exprList[i]; - if (elt) this.toAssignable(elt, isBinding); - } - return exprList; -}; - -// Parses spread element. - -pp.parseSpread = function (refShorthandDefaultPos) { - var node = this.startNode(); - this.next(); - node.argument = this.parseMaybeAssign(refShorthandDefaultPos); - return this.finishNode(node, "SpreadElement"); -}; - -pp.parseRest = function () { - var node = this.startNode(); - this.next(); - node.argument = this.type === tt.name || this.type === tt.bracketL ? this.parseBindingAtom() : this.unexpected(); - return this.finishNode(node, "RestElement"); -}; - -// Parses lvalue (assignable) atom. - -pp.parseBindingAtom = function () { - if (this.options.ecmaVersion < 6) return this.parseIdent(); - switch (this.type) { - case tt.name: - return this.parseIdent(); + // Figure out if it's a module code. + this.strict = this.inModule = this.options.sourceType === "module"; - case tt.bracketL: - var node = this.startNode(); - this.next(); - node.elements = this.parseBindingList(tt.bracketR, true, true); - return this.finishNode(node, "ArrayPattern"); + // Used to signify the start of a potential arrow function + this.potentialArrowAt = -1; - case tt.braceL: - return this.parseObj(true); + // Flags to track whether we are in a function, a generator. + this.inFunction = this.inGenerator = false; + // Labels in scope. + this.labels = []; - default: - this.unexpected(); + // If enabled, skip leading hashbang line. + if (this.pos === 0 && this.options.allowHashBang && this.input.slice(0, 2) === "#!") this.skipLineComment(2); } -}; -pp.parseBindingList = function (close, allowEmpty, allowTrailingComma) { - var elts = [], - first = true; - while (!this.eat(close)) { - if (first) first = false;else this.expect(tt.comma); - if (allowEmpty && this.type === tt.comma) { - elts.push(null); - } else if (allowTrailingComma && this.afterTrailingComma(close)) { - break; - } else if (this.type === tt.ellipsis) { - var rest = this.parseRest(); - this.parseBindingListItem(rest); - elts.push(rest); - this.expect(close); - break; - } else { - var elem = this.parseMaybeDefault(this.start, this.startLoc); - this.parseBindingListItem(elem); - elts.push(elem); - } - } - return elts; -}; + Parser.prototype.extend = function extend(name, f) { + this[name] = f(this[name]); + }; -pp.parseBindingListItem = function (param) { - return param; -}; + Parser.prototype.loadPlugins = function loadPlugins(pluginConfigs) { + for (var _name in pluginConfigs) { + var plugin = plugins[_name]; + if (!plugin) throw new Error("Plugin '" + _name + "' not found"); + plugin(this, pluginConfigs[_name]); + } + }; -// Parses assignment pattern around given atom if possible. + Parser.prototype.parse = function parse() { + var node = this.options.program || this.startNode(); + this.nextToken(); + return this.parseTopLevel(node); + }; -pp.parseMaybeDefault = function (startPos, startLoc, left) { - if (Array.isArray(startPos)) { - if (this.options.locations && noCalls === undefined) { - // shift arguments to left by one - left = startLoc; - // flatten startPos - startLoc = startPos[1]; - startPos = startPos[0]; - } - } - left = left || this.parseBindingAtom(); - if (!this.eat(tt.eq)) return left; - var node = this.startNodeAt(startPos, startLoc); - node.operator = "="; - node.left = left; - node.right = this.parseMaybeAssign(); - return this.finishNode(node, "AssignmentPattern"); -}; + return Parser; +})(); -// Verify that a node is an lval — something that can be assigned -// to. +exports.Parser = Parser; -pp.checkLVal = function (expr, isBinding, checkClashes) { - switch (expr.type) { - case "Identifier": - if (this.strict && (reservedWords.strictBind(expr.name) || reservedWords.strict(expr.name))) this.raise(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode"); - if (checkClashes) { - if (has(checkClashes, expr.name)) this.raise(expr.start, "Argument name clash in strict mode"); - checkClashes[expr.name] = true; - } - break; +},{"./identifier":2,"./options":8,"./tokentype":14,"./whitespace":16}],11:[function(_dereq_,module,exports){ +"use strict"; - case "MemberExpression": - if (isBinding) this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression"); - break; +var _tokentype = _dereq_("./tokentype"); - case "ObjectPattern": - for (var i = 0; i < expr.properties.length; i++) { - this.checkLVal(expr.properties[i].value, isBinding, checkClashes); - }break; +var _state = _dereq_("./state"); - case "ArrayPattern": - for (var i = 0; i < expr.elements.length; i++) { - var elem = expr.elements[i]; - if (elem) this.checkLVal(elem, isBinding, checkClashes); - } - break; +var _whitespace = _dereq_("./whitespace"); - case "AssignmentPattern": - this.checkLVal(expr.left, isBinding, checkClashes); - break; +var pp = _state.Parser.prototype; - case "RestElement": - this.checkLVal(expr.argument, isBinding, checkClashes); - break; +// ### Statement parsing - case "ParenthesizedExpression": - this.checkLVal(expr.expression, isBinding, checkClashes); - break; +// Parse a program. Initializes the parser, reads any number of +// statements, and wraps them in a Program node. Optionally takes a +// `program` argument. If present, the statements will be appended +// to its body instead of creating a new node. - default: - this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue"); +pp.parseTopLevel = function (node) { + var first = true; + if (!node.body) node.body = []; + while (this.type !== _tokentype.types.eof) { + var stmt = this.parseStatement(true, true); + node.body.push(stmt); + if (first) { + if (this.isUseStrict(stmt)) this.setStrict(true); + first = false; + } + } + this.next(); + if (this.options.ecmaVersion >= 6) { + node.sourceType = this.options.sourceType; } + return this.finishNode(node, "Program"); }; -},{"./identifier":7,"./state":13,"./tokentype":17,"./util":18}],10:[function(_dereq_,module,exports){ -"use strict"; - -var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; - -exports.__esModule = true; +var loopLabel = { kind: "loop" }, + switchLabel = { kind: "switch" }; -var Parser = _dereq_("./state").Parser; +// Parse a single statement. +// +// If expecting a statement and finding a slash operator, parse a +// regular expression literal. This is to handle cases like +// `if (foo) /blah/.exec(foo)`, where looking at the previous token +// does not help. -var SourceLocation = _dereq_("./location").SourceLocation; +pp.parseStatement = function (declaration, topLevel) { + var starttype = this.type, + node = this.startNode(); -// Start an AST node, attaching a start offset. + // Most types of statements are recognized by the keyword they + // start with. Many are trivial to parse, some require a bit of + // complexity. -var pp = Parser.prototype; + switch (starttype) { + case _tokentype.types._break:case _tokentype.types._continue: + return this.parseBreakContinueStatement(node, starttype.keyword); + case _tokentype.types._debugger: + return this.parseDebuggerStatement(node); + case _tokentype.types._do: + return this.parseDoStatement(node); + case _tokentype.types._for: + return this.parseForStatement(node); + case _tokentype.types._function: + if (!declaration && this.options.ecmaVersion >= 6) this.unexpected(); + return this.parseFunctionStatement(node); + case _tokentype.types._class: + if (!declaration) this.unexpected(); + return this.parseClass(node, true); + case _tokentype.types._if: + return this.parseIfStatement(node); + case _tokentype.types._return: + return this.parseReturnStatement(node); + case _tokentype.types._switch: + return this.parseSwitchStatement(node); + case _tokentype.types._throw: + return this.parseThrowStatement(node); + case _tokentype.types._try: + return this.parseTryStatement(node); + case _tokentype.types._let:case _tokentype.types._const: + if (!declaration) this.unexpected(); // NOTE: falls through to _var + case _tokentype.types._var: + return this.parseVarStatement(node, starttype); + case _tokentype.types._while: + return this.parseWhileStatement(node); + case _tokentype.types._with: + return this.parseWithStatement(node); + case _tokentype.types.braceL: + return this.parseBlock(); + case _tokentype.types.semi: + return this.parseEmptyStatement(node); + case _tokentype.types._export: + case _tokentype.types._import: + if (!this.options.allowImportExportEverywhere) { + if (!topLevel) this.raise(this.start, "'import' and 'export' may only appear at the top level"); + if (!this.inModule) this.raise(this.start, "'import' and 'export' may appear only with 'sourceType: module'"); + } + return starttype === _tokentype.types._import ? this.parseImport(node) : this.parseExport(node); -var Node = exports.Node = function Node() { - _classCallCheck(this, Node); + // If the statement does not start with a statement keyword or a + // brace, it's an ExpressionStatement or LabeledStatement. We + // simply start parsing an expression, and afterwards, if the + // next token is a colon and the expression was a simple + // Identifier node, we switch to interpreting it as a label. + default: + var maybeName = this.value, + expr = this.parseExpression(); + if (starttype === _tokentype.types.name && expr.type === "Identifier" && this.eat(_tokentype.types.colon)) return this.parseLabeledStatement(node, maybeName, expr);else return this.parseExpressionStatement(node, expr); + } }; -pp.startNode = function () { - var node = new Node(); - node.start = this.start; - if (this.options.locations) node.loc = new SourceLocation(this, this.startLoc); - if (this.options.directSourceFile) node.sourceFile = this.options.directSourceFile; - if (this.options.ranges) node.range = [this.start, 0]; - return node; -}; +pp.parseBreakContinueStatement = function (node, keyword) { + var isBreak = keyword == "break"; + this.next(); + if (this.eat(_tokentype.types.semi) || this.insertSemicolon()) node.label = null;else if (this.type !== _tokentype.types.name) this.unexpected();else { + node.label = this.parseIdent(); + this.semicolon(); + } -pp.startNodeAt = function (pos, loc) { - var node = new Node(); - if (Array.isArray(pos)) { - if (this.options.locations && loc === undefined) { - // flatten pos - loc = pos[1]; - pos = pos[0]; + // Verify that there is an actual destination to break or + // continue to. + for (var i = 0; i < this.labels.length; ++i) { + var lab = this.labels[i]; + if (node.label == null || lab.name === node.label.name) { + if (lab.kind != null && (isBreak || lab.kind === "loop")) break; + if (node.label && isBreak) break; } } - node.start = pos; - if (this.options.locations) node.loc = new SourceLocation(this, loc); - if (this.options.directSourceFile) node.sourceFile = this.options.directSourceFile; - if (this.options.ranges) node.range = [pos, 0]; - return node; + if (i === this.labels.length) this.raise(node.start, "Unsyntactic " + keyword); + return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement"); }; -// Finish an AST node, adding `type` and `end` properties. - -pp.finishNode = function (node, type) { - node.type = type; - node.end = this.lastTokEnd; - if (this.options.locations) node.loc.end = this.lastTokEndLoc; - if (this.options.ranges) node.range[1] = this.lastTokEnd; - return node; +pp.parseDebuggerStatement = function (node) { + this.next(); + this.semicolon(); + return this.finishNode(node, "DebuggerStatement"); }; -// Finish node at given position - -pp.finishNodeAt = function (node, type, pos, loc) { - node.type = type; - if (Array.isArray(pos)) { - if (this.options.locations && loc === undefined) { - // flatten pos - loc = pos[1]; - pos = pos[0]; - } - } - node.end = pos; - if (this.options.locations) node.loc.end = loc; - if (this.options.ranges) node.range[1] = pos; - return node; +pp.parseDoStatement = function (node) { + this.next(); + this.labels.push(loopLabel); + node.body = this.parseStatement(false); + this.labels.pop(); + this.expect(_tokentype.types._while); + node.test = this.parseParenExpression(); + if (this.options.ecmaVersion >= 6) this.eat(_tokentype.types.semi);else this.semicolon(); + return this.finishNode(node, "DoWhileStatement"); }; -},{"./location":8,"./state":13}],11:[function(_dereq_,module,exports){ - - -// Interpret and default an options object - -"use strict"; - -exports.getOptions = getOptions; -exports.__esModule = true; +// Disambiguating between a `for` and a `for`/`in` or `for`/`of` +// loop is non-trivial. Basically, we have to parse the init `var` +// statement or expression, disallowing the `in` operator (see +// the second parameter to `parseExpression`), and then check +// whether the next token is `in` or `of`. When there is no init +// part (semicolon immediately after the opening parenthesis), it +// is a regular `for` loop. -var _util = _dereq_("./util"); +pp.parseForStatement = function (node) { + this.next(); + this.labels.push(loopLabel); + this.expect(_tokentype.types.parenL); + if (this.type === _tokentype.types.semi) return this.parseFor(node, null); + if (this.type === _tokentype.types._var || this.type === _tokentype.types._let || this.type === _tokentype.types._const) { + var _init = this.startNode(), + varKind = this.type; + this.next(); + this.parseVar(_init, true, varKind); + this.finishNode(_init, "VariableDeclaration"); + if ((this.type === _tokentype.types._in || this.options.ecmaVersion >= 6 && this.isContextual("of")) && _init.declarations.length === 1 && !(varKind !== _tokentype.types._var && _init.declarations[0].init)) return this.parseForIn(node, _init); + return this.parseFor(node, _init); + } + var refShorthandDefaultPos = { start: 0 }; + var init = this.parseExpression(true, refShorthandDefaultPos); + if (this.type === _tokentype.types._in || this.options.ecmaVersion >= 6 && this.isContextual("of")) { + this.toAssignable(init); + this.checkLVal(init); + return this.parseForIn(node, init); + } else if (refShorthandDefaultPos.start) { + this.unexpected(refShorthandDefaultPos.start); + } + return this.parseFor(node, init); +}; + +pp.parseFunctionStatement = function (node) { + this.next(); + return this.parseFunction(node, true); +}; + +pp.parseIfStatement = function (node) { + this.next(); + node.test = this.parseParenExpression(); + node.consequent = this.parseStatement(false); + node.alternate = this.eat(_tokentype.types._else) ? this.parseStatement(false) : null; + return this.finishNode(node, "IfStatement"); +}; + +pp.parseReturnStatement = function (node) { + if (!this.inFunction && !this.options.allowReturnOutsideFunction) this.raise(this.start, "'return' outside of function"); + this.next(); + + // In `return` (and `break`/`continue`), the keywords with + // optional arguments, we eagerly look for a semicolon or the + // possibility to insert one. + + if (this.eat(_tokentype.types.semi) || this.insertSemicolon()) node.argument = null;else { + node.argument = this.parseExpression();this.semicolon(); + } + return this.finishNode(node, "ReturnStatement"); +}; + +pp.parseSwitchStatement = function (node) { + this.next(); + node.discriminant = this.parseParenExpression(); + node.cases = []; + this.expect(_tokentype.types.braceL); + this.labels.push(switchLabel); + + // Statements under must be grouped (by label) in SwitchCase + // nodes. `cur` is used to keep the node that we are currently + // adding statements to. + + for (var cur, sawDefault = false; this.type != _tokentype.types.braceR;) { + if (this.type === _tokentype.types._case || this.type === _tokentype.types._default) { + var isCase = this.type === _tokentype.types._case; + if (cur) this.finishNode(cur, "SwitchCase"); + node.cases.push(cur = this.startNode()); + cur.consequent = []; + this.next(); + if (isCase) { + cur.test = this.parseExpression(); + } else { + if (sawDefault) this.raise(this.lastTokStart, "Multiple default clauses"); + sawDefault = true; + cur.test = null; + } + this.expect(_tokentype.types.colon); + } else { + if (!cur) this.unexpected(); + cur.consequent.push(this.parseStatement(true)); + } + } + if (cur) this.finishNode(cur, "SwitchCase"); + this.next(); // Closing brace + this.labels.pop(); + return this.finishNode(node, "SwitchStatement"); +}; + +pp.parseThrowStatement = function (node) { + this.next(); + if (_whitespace.lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) this.raise(this.lastTokEnd, "Illegal newline after throw"); + node.argument = this.parseExpression(); + this.semicolon(); + return this.finishNode(node, "ThrowStatement"); +}; + +// Reused empty array added for node fields that are always empty. + +var empty = []; + +pp.parseTryStatement = function (node) { + this.next(); + node.block = this.parseBlock(); + node.handler = null; + if (this.type === _tokentype.types._catch) { + var clause = this.startNode(); + this.next(); + this.expect(_tokentype.types.parenL); + clause.param = this.parseBindingAtom(); + this.checkLVal(clause.param, true); + this.expect(_tokentype.types.parenR); + clause.guard = null; + clause.body = this.parseBlock(); + node.handler = this.finishNode(clause, "CatchClause"); + } + node.guardedHandlers = empty; + node.finalizer = this.eat(_tokentype.types._finally) ? this.parseBlock() : null; + if (!node.handler && !node.finalizer) this.raise(node.start, "Missing catch or finally clause"); + return this.finishNode(node, "TryStatement"); +}; + +pp.parseVarStatement = function (node, kind) { + this.next(); + this.parseVar(node, false, kind); + this.semicolon(); + return this.finishNode(node, "VariableDeclaration"); +}; + +pp.parseWhileStatement = function (node) { + this.next(); + node.test = this.parseParenExpression(); + this.labels.push(loopLabel); + node.body = this.parseStatement(false); + this.labels.pop(); + return this.finishNode(node, "WhileStatement"); +}; + +pp.parseWithStatement = function (node) { + if (this.strict) this.raise(this.start, "'with' in strict mode"); + this.next(); + node.object = this.parseParenExpression(); + node.body = this.parseStatement(false); + return this.finishNode(node, "WithStatement"); +}; + +pp.parseEmptyStatement = function (node) { + this.next(); + return this.finishNode(node, "EmptyStatement"); +}; + +pp.parseLabeledStatement = function (node, maybeName, expr) { + for (var i = 0; i < this.labels.length; ++i) { + if (this.labels[i].name === maybeName) this.raise(expr.start, "Label '" + maybeName + "' is already declared"); + }var kind = this.type.isLoop ? "loop" : this.type === _tokentype.types._switch ? "switch" : null; + for (var i = this.labels.length - 1; i >= 0; i--) { + var label = this.labels[i]; + if (label.statementStart == node.start) { + label.statementStart = this.start; + label.kind = kind; + } else break; + } + this.labels.push({ name: maybeName, kind: kind, statementStart: this.start }); + node.body = this.parseStatement(true); + this.labels.pop(); + node.label = expr; + return this.finishNode(node, "LabeledStatement"); +}; + +pp.parseExpressionStatement = function (node, expr) { + node.expression = expr; + this.semicolon(); + return this.finishNode(node, "ExpressionStatement"); +}; + +// Parse a semicolon-enclosed block of statements, handling `"use +// strict"` declarations when `allowStrict` is true (used for +// function bodies). + +pp.parseBlock = function (allowStrict) { + var node = this.startNode(), + first = true, + oldStrict = undefined; + node.body = []; + this.expect(_tokentype.types.braceL); + while (!this.eat(_tokentype.types.braceR)) { + var stmt = this.parseStatement(true); + node.body.push(stmt); + if (first && allowStrict && this.isUseStrict(stmt)) { + oldStrict = this.strict; + this.setStrict(this.strict = true); + } + first = false; + } + if (oldStrict === false) this.setStrict(false); + return this.finishNode(node, "BlockStatement"); +}; + +// Parse a regular `for` loop. The disambiguation code in +// `parseStatement` will already have parsed the init statement or +// expression. + +pp.parseFor = function (node, init) { + node.init = init; + this.expect(_tokentype.types.semi); + node.test = this.type === _tokentype.types.semi ? null : this.parseExpression(); + this.expect(_tokentype.types.semi); + node.update = this.type === _tokentype.types.parenR ? null : this.parseExpression(); + this.expect(_tokentype.types.parenR); + node.body = this.parseStatement(false); + this.labels.pop(); + return this.finishNode(node, "ForStatement"); +}; + +// Parse a `for`/`in` and `for`/`of` loop, which are almost +// same from parser's perspective. + +pp.parseForIn = function (node, init) { + var type = this.type === _tokentype.types._in ? "ForInStatement" : "ForOfStatement"; + this.next(); + node.left = init; + node.right = this.parseExpression(); + this.expect(_tokentype.types.parenR); + node.body = this.parseStatement(false); + this.labels.pop(); + return this.finishNode(node, type); +}; + +// Parse a list of variable declarations. + +pp.parseVar = function (node, isFor, kind) { + node.declarations = []; + node.kind = kind.keyword; + for (;;) { + var decl = this.startNode(); + this.parseVarId(decl); + if (this.eat(_tokentype.types.eq)) { + decl.init = this.parseMaybeAssign(isFor); + } else if (kind === _tokentype.types._const && !(this.type === _tokentype.types._in || this.options.ecmaVersion >= 6 && this.isContextual("of"))) { + this.unexpected(); + } else if (decl.id.type != "Identifier" && !(isFor && (this.type === _tokentype.types._in || this.isContextual("of")))) { + this.raise(this.lastTokEnd, "Complex binding patterns require an initialization value"); + } else { + decl.init = null; + } + node.declarations.push(this.finishNode(decl, "VariableDeclarator")); + if (!this.eat(_tokentype.types.comma)) break; + } + return node; +}; + +pp.parseVarId = function (decl) { + decl.id = this.parseBindingAtom(); + this.checkLVal(decl.id, true); +}; + +// Parse a function declaration or literal (depending on the +// `isStatement` parameter). + +pp.parseFunction = function (node, isStatement, allowExpressionBody) { + this.initFunction(node); + if (this.options.ecmaVersion >= 6) node.generator = this.eat(_tokentype.types.star); + if (isStatement || this.type === _tokentype.types.name) node.id = this.parseIdent(); + this.parseFunctionParams(node); + this.parseFunctionBody(node, allowExpressionBody); + return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression"); +}; + +pp.parseFunctionParams = function (node) { + this.expect(_tokentype.types.parenL); + node.params = this.parseBindingList(_tokentype.types.parenR, false, false); +}; + +// Parse a class declaration or literal (depending on the +// `isStatement` parameter). + +pp.parseClass = function (node, isStatement) { + this.next(); + this.parseClassId(node, isStatement); + this.parseClassSuper(node); + var classBody = this.startNode(); + var hadConstructor = false; + classBody.body = []; + this.expect(_tokentype.types.braceL); + while (!this.eat(_tokentype.types.braceR)) { + if (this.eat(_tokentype.types.semi)) continue; + var method = this.startNode(); + var isGenerator = this.eat(_tokentype.types.star); + var isMaybeStatic = this.type === _tokentype.types.name && this.value === "static"; + this.parsePropertyName(method); + method["static"] = isMaybeStatic && this.type !== _tokentype.types.parenL; + if (method["static"]) { + if (isGenerator) this.unexpected(); + isGenerator = this.eat(_tokentype.types.star); + this.parsePropertyName(method); + } + method.kind = "method"; + var isGetSet = false; + if (!method.computed) { + var key = method.key; + + if (!isGenerator && key.type === "Identifier" && this.type !== _tokentype.types.parenL && (key.name === "get" || key.name === "set")) { + isGetSet = true; + method.kind = key.name; + key = this.parsePropertyName(method); + } + if (!method["static"] && (key.type === "Identifier" && key.name === "constructor" || key.type === "Literal" && key.value === "constructor")) { + if (hadConstructor) this.raise(key.start, "Duplicate constructor in the same class"); + if (isGetSet) this.raise(key.start, "Constructor can't have get/set modifier"); + if (isGenerator) this.raise(key.start, "Constructor can't be a generator"); + method.kind = "constructor"; + hadConstructor = true; + } + } + this.parseClassMethod(classBody, method, isGenerator); + if (isGetSet) { + var paramCount = method.kind === "get" ? 0 : 1; + if (method.value.params.length !== paramCount) { + var start = method.value.start; + if (method.kind === "get") this.raise(start, "getter should have no params");else this.raise(start, "setter should have exactly one param"); + } + } + } + node.body = this.finishNode(classBody, "ClassBody"); + return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression"); +}; + +pp.parseClassMethod = function (classBody, method, isGenerator) { + method.value = this.parseMethod(isGenerator); + classBody.body.push(this.finishNode(method, "MethodDefinition")); +}; + +pp.parseClassId = function (node, isStatement) { + node.id = this.type === _tokentype.types.name ? this.parseIdent() : isStatement ? this.unexpected() : null; +}; + +pp.parseClassSuper = function (node) { + node.superClass = this.eat(_tokentype.types._extends) ? this.parseExprSubscripts() : null; +}; + +// Parses module export declaration. + +pp.parseExport = function (node) { + this.next(); + // export * from '...' + if (this.eat(_tokentype.types.star)) { + this.expectContextual("from"); + node.source = this.type === _tokentype.types.string ? this.parseExprAtom() : this.unexpected(); + this.semicolon(); + return this.finishNode(node, "ExportAllDeclaration"); + } + if (this.eat(_tokentype.types._default)) { + // export default ... + var expr = this.parseMaybeAssign(); + var needsSemi = true; + if (expr.type == "FunctionExpression" || expr.type == "ClassExpression") { + needsSemi = false; + if (expr.id) { + expr.type = expr.type == "FunctionExpression" ? "FunctionDeclaration" : "ClassDeclaration"; + } + } + node.declaration = expr; + if (needsSemi) this.semicolon(); + return this.finishNode(node, "ExportDefaultDeclaration"); + } + // export var|const|let|function|class ... + if (this.shouldParseExportStatement()) { + node.declaration = this.parseStatement(true); + node.specifiers = []; + node.source = null; + } else { + // export { x, y as z } [from '...'] + node.declaration = null; + node.specifiers = this.parseExportSpecifiers(); + if (this.eatContextual("from")) { + node.source = this.type === _tokentype.types.string ? this.parseExprAtom() : this.unexpected(); + } else { + node.source = null; + } + this.semicolon(); + } + return this.finishNode(node, "ExportNamedDeclaration"); +}; + +pp.shouldParseExportStatement = function () { + return this.type.keyword; +}; + +// Parses a comma-separated list of module exports. + +pp.parseExportSpecifiers = function () { + var nodes = [], + first = true; + // export { x, y as z } [from '...'] + this.expect(_tokentype.types.braceL); + while (!this.eat(_tokentype.types.braceR)) { + if (!first) { + this.expect(_tokentype.types.comma); + if (this.afterTrailingComma(_tokentype.types.braceR)) break; + } else first = false; + + var node = this.startNode(); + node.local = this.parseIdent(this.type === _tokentype.types._default); + node.exported = this.eatContextual("as") ? this.parseIdent(true) : node.local; + nodes.push(this.finishNode(node, "ExportSpecifier")); + } + return nodes; +}; + +// Parses import declaration. + +pp.parseImport = function (node) { + this.next(); + // import '...' + if (this.type === _tokentype.types.string) { + node.specifiers = empty; + node.source = this.parseExprAtom(); + node.kind = ""; + } else { + node.specifiers = this.parseImportSpecifiers(); + this.expectContextual("from"); + node.source = this.type === _tokentype.types.string ? this.parseExprAtom() : this.unexpected(); + } + this.semicolon(); + return this.finishNode(node, "ImportDeclaration"); +}; + +// Parses a comma-separated list of module imports. + +pp.parseImportSpecifiers = function () { + var nodes = [], + first = true; + if (this.type === _tokentype.types.name) { + // import defaultObj, { x, y as z } from '...' + var node = this.startNode(); + node.local = this.parseIdent(); + this.checkLVal(node.local, true); + nodes.push(this.finishNode(node, "ImportDefaultSpecifier")); + if (!this.eat(_tokentype.types.comma)) return nodes; + } + if (this.type === _tokentype.types.star) { + var node = this.startNode(); + this.next(); + this.expectContextual("as"); + node.local = this.parseIdent(); + this.checkLVal(node.local, true); + nodes.push(this.finishNode(node, "ImportNamespaceSpecifier")); + return nodes; + } + this.expect(_tokentype.types.braceL); + while (!this.eat(_tokentype.types.braceR)) { + if (!first) { + this.expect(_tokentype.types.comma); + if (this.afterTrailingComma(_tokentype.types.braceR)) break; + } else first = false; + + var node = this.startNode(); + node.imported = this.parseIdent(true); + node.local = this.eatContextual("as") ? this.parseIdent() : node.imported; + this.checkLVal(node.local, true); + nodes.push(this.finishNode(node, "ImportSpecifier")); + } + return nodes; +}; + +},{"./state":10,"./tokentype":14,"./whitespace":16}],12:[function(_dereq_,module,exports){ +// The algorithm used to determine whether a regexp can appear at a +// given point in the program is loosely based on sweet.js' approach. +// See https://github.com/mozilla/sweet.js/wiki/design + +"use strict"; + +exports.__esModule = true; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var _state = _dereq_("./state"); + +var _tokentype = _dereq_("./tokentype"); + +var _whitespace = _dereq_("./whitespace"); + +var TokContext = function TokContext(token, isExpr, preserveSpace, override) { + _classCallCheck(this, TokContext); + + this.token = token; + this.isExpr = !!isExpr; + this.preserveSpace = !!preserveSpace; + this.override = override; +}; + +exports.TokContext = TokContext; +var types = { + b_stat: new TokContext("{", false), + b_expr: new TokContext("{", true), + b_tmpl: new TokContext("${", true), + p_stat: new TokContext("(", false), + p_expr: new TokContext("(", true), + q_tmpl: new TokContext("`", true, true, function (p) { + return p.readTmplToken(); + }), + f_expr: new TokContext("function", true) +}; + +exports.types = types; +var pp = _state.Parser.prototype; + +pp.initialContext = function () { + return [types.b_stat]; +}; + +pp.braceIsBlock = function (prevType) { + if (prevType === _tokentype.types.colon) { + var _parent = this.curContext(); + if (_parent === types.b_stat || _parent === types.b_expr) return !_parent.isExpr; + } + if (prevType === _tokentype.types._return) return _whitespace.lineBreak.test(this.input.slice(this.lastTokEnd, this.start)); + if (prevType === _tokentype.types._else || prevType === _tokentype.types.semi || prevType === _tokentype.types.eof || prevType === _tokentype.types.parenR) return true; + if (prevType == _tokentype.types.braceL) return this.curContext() === types.b_stat; + return !this.exprAllowed; +}; + +pp.updateContext = function (prevType) { + var update = undefined, + type = this.type; + if (type.keyword && prevType == _tokentype.types.dot) this.exprAllowed = false;else if (update = type.updateContext) update.call(this, prevType);else this.exprAllowed = type.beforeExpr; +}; + +// Token-specific context update code + +_tokentype.types.parenR.updateContext = _tokentype.types.braceR.updateContext = function () { + if (this.context.length == 1) { + this.exprAllowed = true; + return; + } + var out = this.context.pop(); + if (out === types.b_stat && this.curContext() === types.f_expr) { + this.context.pop(); + this.exprAllowed = false; + } else if (out === types.b_tmpl) { + this.exprAllowed = true; + } else { + this.exprAllowed = !out.isExpr; + } +}; + +_tokentype.types.braceL.updateContext = function (prevType) { + this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr); + this.exprAllowed = true; +}; + +_tokentype.types.dollarBraceL.updateContext = function () { + this.context.push(types.b_tmpl); + this.exprAllowed = true; +}; + +_tokentype.types.parenL.updateContext = function (prevType) { + var statementParens = prevType === _tokentype.types._if || prevType === _tokentype.types._for || prevType === _tokentype.types._with || prevType === _tokentype.types._while; + this.context.push(statementParens ? types.p_stat : types.p_expr); + this.exprAllowed = true; +}; + +_tokentype.types.incDec.updateContext = function () {}; + +_tokentype.types._function.updateContext = function () { + if (this.curContext() !== types.b_stat) this.context.push(types.f_expr); + this.exprAllowed = false; +}; + +_tokentype.types.backQuote.updateContext = function () { + if (this.curContext() === types.q_tmpl) this.context.pop();else this.context.push(types.q_tmpl); + this.exprAllowed = false; +}; + +// tokExprAllowed stays unchanged + +},{"./state":10,"./tokentype":14,"./whitespace":16}],13:[function(_dereq_,module,exports){ +"use strict"; + +exports.__esModule = true; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var _identifier = _dereq_("./identifier"); + +var _tokentype = _dereq_("./tokentype"); + +var _state = _dereq_("./state"); + +var _locutil = _dereq_("./locutil"); + +var _whitespace = _dereq_("./whitespace"); + +// Object type used to represent tokens. Note that normally, tokens +// simply exist as properties on the parser object. This is only +// used for the onToken callback and the external tokenizer. + +var Token = function Token(p) { + _classCallCheck(this, Token); + + this.type = p.type; + this.value = p.value; + this.start = p.start; + this.end = p.end; + if (p.options.locations) this.loc = new _locutil.SourceLocation(p, p.startLoc, p.endLoc); + if (p.options.ranges) this.range = [p.start, p.end]; +}; + +exports.Token = Token; + +// ## Tokenizer + +var pp = _state.Parser.prototype; + +// Are we running under Rhino? +var isRhino = typeof Packages == "object" && Object.prototype.toString.call(Packages) == "[object JavaPackage]"; + +// Move to the next token + +pp.next = function () { + if (this.options.onToken) this.options.onToken(new Token(this)); + + this.lastTokEnd = this.end; + this.lastTokStart = this.start; + this.lastTokEndLoc = this.endLoc; + this.lastTokStartLoc = this.startLoc; + this.nextToken(); +}; + +pp.getToken = function () { + this.next(); + return new Token(this); +}; + +// If we're in an ES6 environment, make parsers iterable +if (typeof Symbol !== "undefined") pp[Symbol.iterator] = function () { + var self = this; + return { next: function next() { + var token = self.getToken(); + return { + done: token.type === _tokentype.types.eof, + value: token + }; + } }; +}; + +// Toggle strict mode. Re-reads the next number or string to please +// pedantic tests (`"use strict"; 010;` should fail). + +pp.setStrict = function (strict) { + this.strict = strict; + if (this.type !== _tokentype.types.num && this.type !== _tokentype.types.string) return; + this.pos = this.start; + if (this.options.locations) { + while (this.pos < this.lineStart) { + this.lineStart = this.input.lastIndexOf("\n", this.lineStart - 2) + 1; + --this.curLine; + } + } + this.nextToken(); +}; + +pp.curContext = function () { + return this.context[this.context.length - 1]; +}; + +// Read a single token, updating the parser object's token-related +// properties. + +pp.nextToken = function () { + var curContext = this.curContext(); + if (!curContext || !curContext.preserveSpace) this.skipSpace(); + + this.start = this.pos; + if (this.options.locations) this.startLoc = this.curPosition(); + if (this.pos >= this.input.length) return this.finishToken(_tokentype.types.eof); + + if (curContext.override) return curContext.override(this);else this.readToken(this.fullCharCodeAtPos()); +}; + +pp.readToken = function (code) { + // Identifier or keyword. '\uXXXX' sequences are allowed in + // identifiers, so '\' also dispatches to that. + if (_identifier.isIdentifierStart(code, this.options.ecmaVersion >= 6) || code === 92 /* '\' */) return this.readWord(); + + return this.getTokenFromCode(code); +}; + +pp.fullCharCodeAtPos = function () { + var code = this.input.charCodeAt(this.pos); + if (code <= 0xd7ff || code >= 0xe000) return code; + var next = this.input.charCodeAt(this.pos + 1); + return (code << 10) + next - 0x35fdc00; +}; + +pp.skipBlockComment = function () { + var startLoc = this.options.onComment && this.curPosition(); + var start = this.pos, + end = this.input.indexOf("*/", this.pos += 2); + if (end === -1) this.raise(this.pos - 2, "Unterminated comment"); + this.pos = end + 2; + if (this.options.locations) { + _whitespace.lineBreakG.lastIndex = start; + var match = undefined; + while ((match = _whitespace.lineBreakG.exec(this.input)) && match.index < this.pos) { + ++this.curLine; + this.lineStart = match.index + match[0].length; + } + } + if (this.options.onComment) this.options.onComment(true, this.input.slice(start + 2, end), start, this.pos, startLoc, this.curPosition()); +}; + +pp.skipLineComment = function (startSkip) { + var start = this.pos; + var startLoc = this.options.onComment && this.curPosition(); + var ch = this.input.charCodeAt(this.pos += startSkip); + while (this.pos < this.input.length && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) { + ++this.pos; + ch = this.input.charCodeAt(this.pos); + } + if (this.options.onComment) this.options.onComment(false, this.input.slice(start + startSkip, this.pos), start, this.pos, startLoc, this.curPosition()); +}; + +// Called at the start of the parse and after every token. Skips +// whitespace and comments, and. + +pp.skipSpace = function () { + loop: while (this.pos < this.input.length) { + var ch = this.input.charCodeAt(this.pos); + switch (ch) { + case 32:case 160: + // ' ' + ++this.pos; + break; + case 13: + if (this.input.charCodeAt(this.pos + 1) === 10) { + ++this.pos; + } + case 10:case 8232:case 8233: + ++this.pos; + if (this.options.locations) { + ++this.curLine; + this.lineStart = this.pos; + } + break; + case 47: + // '/' + switch (this.input.charCodeAt(this.pos + 1)) { + case 42: + // '*' + this.skipBlockComment(); + break; + case 47: + this.skipLineComment(2); + break; + default: + break loop; + } + break; + default: + if (ch > 8 && ch < 14 || ch >= 5760 && _whitespace.nonASCIIwhitespace.test(String.fromCharCode(ch))) { + ++this.pos; + } else { + break loop; + } + } + } +}; + +// Called at the end of every token. Sets `end`, `val`, and +// maintains `context` and `exprAllowed`, and skips the space after +// the token, so that the next one's `start` will point at the +// right position. + +pp.finishToken = function (type, val) { + this.end = this.pos; + if (this.options.locations) this.endLoc = this.curPosition(); + var prevType = this.type; + this.type = type; + this.value = val; + + this.updateContext(prevType); +}; + +// ### Token reading + +// This is the function that is called to fetch the next token. It +// is somewhat obscure, because it works in character codes rather +// than characters, and because operator parsing has been inlined +// into it. +// +// All in the name of speed. +// +pp.readToken_dot = function () { + var next = this.input.charCodeAt(this.pos + 1); + if (next >= 48 && next <= 57) return this.readNumber(true); + var next2 = this.input.charCodeAt(this.pos + 2); + if (this.options.ecmaVersion >= 6 && next === 46 && next2 === 46) { + // 46 = dot '.' + this.pos += 3; + return this.finishToken(_tokentype.types.ellipsis); + } else { + ++this.pos; + return this.finishToken(_tokentype.types.dot); + } +}; + +pp.readToken_slash = function () { + // '/' + var next = this.input.charCodeAt(this.pos + 1); + if (this.exprAllowed) { + ++this.pos;return this.readRegexp(); + } + if (next === 61) return this.finishOp(_tokentype.types.assign, 2); + return this.finishOp(_tokentype.types.slash, 1); +}; + +pp.readToken_mult_modulo = function (code) { + // '%*' + var next = this.input.charCodeAt(this.pos + 1); + if (next === 61) return this.finishOp(_tokentype.types.assign, 2); + return this.finishOp(code === 42 ? _tokentype.types.star : _tokentype.types.modulo, 1); +}; + +pp.readToken_pipe_amp = function (code) { + // '|&' + var next = this.input.charCodeAt(this.pos + 1); + if (next === code) return this.finishOp(code === 124 ? _tokentype.types.logicalOR : _tokentype.types.logicalAND, 2); + if (next === 61) return this.finishOp(_tokentype.types.assign, 2); + return this.finishOp(code === 124 ? _tokentype.types.bitwiseOR : _tokentype.types.bitwiseAND, 1); +}; + +pp.readToken_caret = function () { + // '^' + var next = this.input.charCodeAt(this.pos + 1); + if (next === 61) return this.finishOp(_tokentype.types.assign, 2); + return this.finishOp(_tokentype.types.bitwiseXOR, 1); +}; + +pp.readToken_plus_min = function (code) { + // '+-' + var next = this.input.charCodeAt(this.pos + 1); + if (next === code) { + if (next == 45 && this.input.charCodeAt(this.pos + 2) == 62 && _whitespace.lineBreak.test(this.input.slice(this.lastTokEnd, this.pos))) { + // A `-->` line comment + this.skipLineComment(3); + this.skipSpace(); + return this.nextToken(); + } + return this.finishOp(_tokentype.types.incDec, 2); + } + if (next === 61) return this.finishOp(_tokentype.types.assign, 2); + return this.finishOp(_tokentype.types.plusMin, 1); +}; + +pp.readToken_lt_gt = function (code) { + // '<>' + var next = this.input.charCodeAt(this.pos + 1); + var size = 1; + if (next === code) { + size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2; + if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(_tokentype.types.assign, size + 1); + return this.finishOp(_tokentype.types.bitShift, size); + } + if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 && this.input.charCodeAt(this.pos + 3) == 45) { + if (this.inModule) this.unexpected(); + // `` line comment - this.skipLineComment(3); - this.skipSpace(); - return this.nextToken(); - } - return this.finishOp(tt.incDec, 2); - } - if (next === 61) return this.finishOp(tt.assign, 2); - return this.finishOp(tt.plusMin, 1); -}; + return map; + }; -pp.readToken_lt_gt = function (code) { - // '<>' - var next = this.input.charCodeAt(this.pos + 1); - var size = 1; - if (next === code) { - size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2; - if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1); - return this.finishOp(tt.bitShift, size); - } - if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 && this.input.charCodeAt(this.pos + 3) == 45) { - if (this.inModule) this.unexpected(); - // `/lib/droplet.css"> /lib/jquery-ui-slider-pips.css"> -/lib/nouislider.css"> /lib/font-awesome.css"> /lib/tooltipster/css/tooltipster.css"> diff --git a/content/lib/droplet.js b/content/lib/droplet.js index 488d8b18..b813293a 100644 --- a/content/lib/droplet.js +++ b/content/lib/droplet.js @@ -2,7 +2,7 @@ * Copyright (c) 2015 Anthony Bau. * MIT License. * - * Date: 2015-07-20 + * Date: 2015-07-23 */ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.droplet = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o - Copyright (c) 2015 Niklas von Hertzen - Released under MIT License -*/ - -(function(window, document, exports, global, define, undefined){ - -/*! - * @overview es6-promise - a tiny implementation of Promises/A+. - * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) - * @license Licensed under MIT license - * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE - * @version 2.0.1 - */ - -(function(){function r(a,b){n[l]=a;n[l+1]=b;l+=2;2===l&&A()}function s(a){return"function"===typeof a}function F(){return function(){process.nextTick(t)}}function G(){var a=0,b=new B(t),c=document.createTextNode("");b.observe(c,{characterData:!0});return function(){c.data=a=++a%2}}function H(){var a=new MessageChannel;a.port1.onmessage=t;return function(){a.port2.postMessage(0)}}function I(){return function(){setTimeout(t,1)}}function t(){for(var a=0;a= 0x80 (not a basic code point)', - 'invalid-input': 'Invalid input' - }, - - /** Convenience shortcuts */ - baseMinusTMin = base - tMin, - floor = Math.floor, - stringFromCharCode = String.fromCharCode, - - /** Temporary variable */ - key; - - /*--------------------------------------------------------------------------*/ - - /** - * A generic error utility function. - * @private - * @param {String} type The error type. - * @returns {Error} Throws a `RangeError` with the applicable error message. - */ - function error(type) { - throw RangeError(errors[type]); - } - - /** - * A generic `Array#map` utility function. - * @private - * @param {Array} array The array to iterate over. - * @param {Function} callback The function that gets called for every array - * item. - * @returns {Array} A new array of values returned by the callback function. - */ - function map(array, fn) { - var length = array.length; - var result = []; - while (length--) { - result[length] = fn(array[length]); - } - return result; - } - - /** - * A simple `Array#map`-like wrapper to work with domain name strings or email - * addresses. - * @private - * @param {String} domain The domain name or email address. - * @param {Function} callback The function that gets called for every - * character. - * @returns {Array} A new string of characters returned by the callback - * function. - */ - function mapDomain(string, fn) { - var parts = string.split('@'); - var result = ''; - if (parts.length > 1) { - // In email addresses, only the domain name should be punycoded. Leave - // the local part (i.e. everything up to `@`) intact. - result = parts[0] + '@'; - string = parts[1]; - } - var labels = string.split(regexSeparators); - var encoded = map(labels, fn).join('.'); - return result + encoded; - } - - /** - * Creates an array containing the numeric code points of each Unicode - * character in the string. While JavaScript uses UCS-2 internally, - * this function will convert a pair of surrogate halves (each of which - * UCS-2 exposes as separate characters) into a single code point, - * matching UTF-16. - * @see `punycode.ucs2.encode` - * @see - * @memberOf punycode.ucs2 - * @name decode - * @param {String} string The Unicode input string (UCS-2). - * @returns {Array} The new array of code points. - */ - function ucs2decode(string) { - var output = [], - counter = 0, - length = string.length, - value, - extra; - while (counter < length) { - value = string.charCodeAt(counter++); - if (value >= 0xD800 && value <= 0xDBFF && counter < length) { - // high surrogate, and there is a next character - extra = string.charCodeAt(counter++); - if ((extra & 0xFC00) == 0xDC00) { // low surrogate - output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); - } else { - // unmatched surrogate; only append this code unit, in case the next - // code unit is the high surrogate of a surrogate pair - output.push(value); - counter--; - } - } else { - output.push(value); - } - } - return output; - } - - /** - * Creates a string based on an array of numeric code points. - * @see `punycode.ucs2.decode` - * @memberOf punycode.ucs2 - * @name encode - * @param {Array} codePoints The array of numeric code points. - * @returns {String} The new Unicode string (UCS-2). - */ - function ucs2encode(array) { - return map(array, function(value) { - var output = ''; - if (value > 0xFFFF) { - value -= 0x10000; - output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); - value = 0xDC00 | value & 0x3FF; - } - output += stringFromCharCode(value); - return output; - }).join(''); - } - - /** - * Converts a basic code point into a digit/integer. - * @see `digitToBasic()` - * @private - * @param {Number} codePoint The basic numeric code point value. - * @returns {Number} The numeric value of a basic code point (for use in - * representing integers) in the range `0` to `base - 1`, or `base` if - * the code point does not represent a value. - */ - function basicToDigit(codePoint) { - if (codePoint - 48 < 10) { - return codePoint - 22; - } - if (codePoint - 65 < 26) { - return codePoint - 65; - } - if (codePoint - 97 < 26) { - return codePoint - 97; - } - return base; - } - - /** - * Converts a digit/integer into a basic code point. - * @see `basicToDigit()` - * @private - * @param {Number} digit The numeric value of a basic code point. - * @returns {Number} The basic code point whose value (when used for - * representing integers) is `digit`, which needs to be in the range - * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is - * used; else, the lowercase form is used. The behavior is undefined - * if `flag` is non-zero and `digit` has no uppercase form. - */ - function digitToBasic(digit, flag) { - // 0..25 map to ASCII a..z or A..Z - // 26..35 map to ASCII 0..9 - return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); - } - - /** - * Bias adaptation function as per section 3.4 of RFC 3492. - * http://tools.ietf.org/html/rfc3492#section-3.4 - * @private - */ - function adapt(delta, numPoints, firstTime) { - var k = 0; - delta = firstTime ? floor(delta / damp) : delta >> 1; - delta += floor(delta / numPoints); - for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { - delta = floor(delta / baseMinusTMin); - } - return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); - } - - /** - * Converts a Punycode string of ASCII-only symbols to a string of Unicode - * symbols. - * @memberOf punycode - * @param {String} input The Punycode string of ASCII-only symbols. - * @returns {String} The resulting string of Unicode symbols. - */ - function decode(input) { - // Don't use UCS-2 - var output = [], - inputLength = input.length, - out, - i = 0, - n = initialN, - bias = initialBias, - basic, - j, - index, - oldi, - w, - k, - digit, - t, - /** Cached calculation results */ - baseMinusT; - - // Handle the basic code points: let `basic` be the number of input code - // points before the last delimiter, or `0` if there is none, then copy - // the first basic code points to the output. - - basic = input.lastIndexOf(delimiter); - if (basic < 0) { - basic = 0; - } - - for (j = 0; j < basic; ++j) { - // if it's not a basic code point - if (input.charCodeAt(j) >= 0x80) { - error('not-basic'); - } - output.push(input.charCodeAt(j)); - } - - // Main decoding loop: start just after the last delimiter if any basic code - // points were copied; start at the beginning otherwise. - - for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { - - // `index` is the index of the next character to be consumed. - // Decode a generalized variable-length integer into `delta`, - // which gets added to `i`. The overflow checking is easier - // if we increase `i` as we go, then subtract off its starting - // value at the end to obtain `delta`. - for (oldi = i, w = 1, k = base; /* no condition */; k += base) { - - if (index >= inputLength) { - error('invalid-input'); - } - - digit = basicToDigit(input.charCodeAt(index++)); - - if (digit >= base || digit > floor((maxInt - i) / w)) { - error('overflow'); - } - - i += digit * w; - t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); - - if (digit < t) { - break; - } - - baseMinusT = base - t; - if (w > floor(maxInt / baseMinusT)) { - error('overflow'); - } - - w *= baseMinusT; - - } - - out = output.length + 1; - bias = adapt(i - oldi, out, oldi == 0); - - // `i` was supposed to wrap around from `out` to `0`, - // incrementing `n` each time, so we'll fix that now: - if (floor(i / out) > maxInt - n) { - error('overflow'); - } - - n += floor(i / out); - i %= out; - - // Insert `n` at position `i` of the output - output.splice(i++, 0, n); - - } - - return ucs2encode(output); - } - - /** - * Converts a string of Unicode symbols (e.g. a domain name label) to a - * Punycode string of ASCII-only symbols. - * @memberOf punycode - * @param {String} input The string of Unicode symbols. - * @returns {String} The resulting Punycode string of ASCII-only symbols. - */ - function encode(input) { - var n, - delta, - handledCPCount, - basicLength, - bias, - j, - m, - q, - k, - t, - currentValue, - output = [], - /** `inputLength` will hold the number of code points in `input`. */ - inputLength, - /** Cached calculation results */ - handledCPCountPlusOne, - baseMinusT, - qMinusT; - - // Convert the input in UCS-2 to Unicode - input = ucs2decode(input); - - // Cache the length - inputLength = input.length; - - // Initialize the state - n = initialN; - delta = 0; - bias = initialBias; - - // Handle the basic code points - for (j = 0; j < inputLength; ++j) { - currentValue = input[j]; - if (currentValue < 0x80) { - output.push(stringFromCharCode(currentValue)); - } - } - - handledCPCount = basicLength = output.length; - - // `handledCPCount` is the number of code points that have been handled; - // `basicLength` is the number of basic code points. - - // Finish the basic string - if it is not empty - with a delimiter - if (basicLength) { - output.push(delimiter); - } - - // Main encoding loop: - while (handledCPCount < inputLength) { - - // All non-basic code points < n have been handled already. Find the next - // larger one: - for (m = maxInt, j = 0; j < inputLength; ++j) { - currentValue = input[j]; - if (currentValue >= n && currentValue < m) { - m = currentValue; - } - } - - // Increase `delta` enough to advance the decoder's state to , - // but guard against overflow - handledCPCountPlusOne = handledCPCount + 1; - if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { - error('overflow'); - } - - delta += (m - n) * handledCPCountPlusOne; - n = m; - - for (j = 0; j < inputLength; ++j) { - currentValue = input[j]; - - if (currentValue < n && ++delta > maxInt) { - error('overflow'); - } - - if (currentValue == n) { - // Represent delta as a generalized variable-length integer - for (q = delta, k = base; /* no condition */; k += base) { - t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); - if (q < t) { - break; - } - qMinusT = q - t; - baseMinusT = base - t; - output.push( - stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) - ); - q = floor(qMinusT / baseMinusT); - } - - output.push(stringFromCharCode(digitToBasic(q, 0))); - bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); - delta = 0; - ++handledCPCount; - } - } - - ++delta; - ++n; - - } - return output.join(''); - } - - /** - * Converts a Punycode string representing a domain name or an email address - * to Unicode. Only the Punycoded parts of the input will be converted, i.e. - * it doesn't matter if you call it on a string that has already been - * converted to Unicode. - * @memberOf punycode - * @param {String} input The Punycoded domain name or email address to - * convert to Unicode. - * @returns {String} The Unicode representation of the given Punycode - * string. - */ - function toUnicode(input) { - return mapDomain(input, function(string) { - return regexPunycode.test(string) - ? decode(string.slice(4).toLowerCase()) - : string; - }); - } - - /** - * Converts a Unicode string representing a domain name or an email address to - * Punycode. Only the non-ASCII parts of the domain name will be converted, - * i.e. it doesn't matter if you call it with a domain that's already in - * ASCII. - * @memberOf punycode - * @param {String} input The domain name or email address to convert, as a - * Unicode string. - * @returns {String} The Punycode representation of the given domain name or - * email address. - */ - function toASCII(input) { - return mapDomain(input, function(string) { - return regexNonASCII.test(string) - ? 'xn--' + encode(string) - : string; - }); - } - - /*--------------------------------------------------------------------------*/ - - /** Define the public API */ - punycode = { - /** - * A string representing the current Punycode.js version number. - * @memberOf punycode - * @type String - */ - 'version': '1.3.1', - /** - * An object of methods to convert from JavaScript's internal character - * representation (UCS-2) to Unicode code points, and back. - * @see - * @memberOf punycode - * @type Object - */ - 'ucs2': { - 'decode': ucs2decode, - 'encode': ucs2encode - }, - 'decode': decode, - 'encode': encode, - 'toASCII': toASCII, - 'toUnicode': toUnicode - }; - - /** Expose `punycode` */ - // Some AMD build optimizers, like r.js, check for specific condition patterns - // like the following: - if ( - typeof define == 'function' && - typeof define.amd == 'object' && - define.amd - ) { - define('punycode', function() { - return punycode; - }); - } else if (freeExports && freeModule) { - if (module.exports == freeExports) { // in Node.js or RingoJS v0.8.0+ - freeModule.exports = punycode; - } else { // in Narwhal or RingoJS v0.7.0- - for (key in punycode) { - punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); - } - } - } else { // in Rhino or a web browser - root.punycode = punycode; - } - -}(this)); - -var html2canvasNodeAttribute = "data-html2canvas-node"; -var html2canvasCanvasCloneAttribute = "data-html2canvas-canvas-clone"; -var html2canvasCanvasCloneIndex = 0; -var html2canvasCloneIndex = 0; - -window.html2canvas = function(nodeList, options) { - var index = html2canvasCloneIndex++; - options = options || {}; - if (options.logging) { - window.html2canvas.logging = true; - window.html2canvas.start = Date.now(); - } - - options.async = typeof(options.async) === "undefined" ? true : options.async; - options.allowTaint = typeof(options.allowTaint) === "undefined" ? false : options.allowTaint; - options.removeContainer = typeof(options.removeContainer) === "undefined" ? true : options.removeContainer; - options.javascriptEnabled = typeof(options.javascriptEnabled) === "undefined" ? false : options.javascriptEnabled; - options.imageTimeout = typeof(options.imageTimeout) === "undefined" ? 10000 : options.imageTimeout; - options.renderer = typeof(options.renderer) === "function" ? options.renderer : CanvasRenderer; - options.strict = !!options.strict; - - if (typeof(nodeList) === "string") { - if (typeof(options.proxy) !== "string") { - return Promise.reject("Proxy must be used when rendering url"); - } - var width = options.width != null ? options.width : window.innerWidth; - var height = options.height != null ? options.height : window.innerHeight; - return loadUrlDocument(absoluteUrl(nodeList), options.proxy, document, width, height, options).then(function(container) { - return renderWindow(container.contentWindow.document.documentElement, container, options, width, height); - }); - } - - var node = ((nodeList === undefined) ? [document.documentElement] : ((nodeList.length) ? nodeList : [nodeList]))[0]; - node.setAttribute(html2canvasNodeAttribute + index, index); - return renderDocument(node.ownerDocument, options, node.ownerDocument.defaultView.innerWidth, node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) { - if (typeof(options.onrendered) === "function") { - log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas"); - options.onrendered(canvas); - } - return canvas; - }); -}; - -window.html2canvas.punycode = this.punycode; -window.html2canvas.proxy = {}; - -function renderDocument(document, options, windowWidth, windowHeight, html2canvasIndex) { - return createWindowClone(document, document, windowWidth, windowHeight, options, document.defaultView.pageXOffset, document.defaultView.pageYOffset).then(function(container) { - log("Document cloned"); - var attributeName = html2canvasNodeAttribute + html2canvasIndex; - var selector = "[" + attributeName + "='" + html2canvasIndex + "']"; - document.querySelector(selector).removeAttribute(attributeName); - var clonedWindow = container.contentWindow; - var node = clonedWindow.document.querySelector(selector); - var oncloneHandler = (typeof(options.onclone) === "function") ? Promise.resolve(options.onclone(clonedWindow.document)) : Promise.resolve(true); - return oncloneHandler.then(function() { - return renderWindow(node, container, options, windowWidth, windowHeight); - }); - }); -} - -function renderWindow(node, container, options, windowWidth, windowHeight) { - var clonedWindow = container.contentWindow; - var support = new Support(clonedWindow.document); - var imageLoader = new ImageLoader(options, support); - var bounds = getBounds(node); - var width = options.type === "view" ? windowWidth : documentWidth(clonedWindow.document); - var height = options.type === "view" ? windowHeight : documentHeight(clonedWindow.document); - var renderer = new options.renderer(width, height, imageLoader, options, document); - var parser = new NodeParser(node, renderer, support, imageLoader, options); - return parser.ready.then(function() { - log("Finished rendering"); - var canvas; - - if (options.type === "view") { - canvas = crop(renderer.canvas, {width: renderer.canvas.width, height: renderer.canvas.height, top: 0, left: 0, x: 0, y: 0}); - } else if (node === clonedWindow.document.body || node === clonedWindow.document.documentElement || options.canvas != null) { - canvas = renderer.canvas; - } else { - canvas = crop(renderer.canvas, {width: options.width != null ? options.width : bounds.width, height: options.height != null ? options.height : bounds.height, top: bounds.top, left: bounds.left, x: clonedWindow.pageXOffset, y: clonedWindow.pageYOffset}); - } - - cleanupContainer(container, options); - return canvas; - }); -} - -function cleanupContainer(container, options) { - if (options.removeContainer) { - container.parentNode.removeChild(container); - log("Cleaned up container"); - } -} - -function crop(canvas, bounds) { - var croppedCanvas = document.createElement("canvas"); - var x1 = Math.min(canvas.width - 1, Math.max(0, bounds.left)); - var x2 = Math.min(canvas.width, Math.max(1, bounds.left + bounds.width)); - var y1 = Math.min(canvas.height - 1, Math.max(0, bounds.top)); - var y2 = Math.min(canvas.height, Math.max(1, bounds.top + bounds.height)); - croppedCanvas.width = bounds.width; - croppedCanvas.height = bounds.height; - log("Cropping canvas at:", "left:", bounds.left, "top:", bounds.top, "width:", (x2-x1), "height:", (y2-y1)); - log("Resulting crop with width", bounds.width, "and height", bounds.height, " with x", x1, "and y", y1); - croppedCanvas.getContext("2d").drawImage(canvas, x1, y1, x2-x1, y2-y1, bounds.x, bounds.y, x2-x1, y2-y1); - return croppedCanvas; -} - -function documentWidth (doc) { - return Math.max( - Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth), - Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth), - Math.max(doc.body.clientWidth, doc.documentElement.clientWidth) - ); -} - -function documentHeight (doc) { - return Math.max( - Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight), - Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight), - Math.max(doc.body.clientHeight, doc.documentElement.clientHeight) - ); -} - -function smallImage() { - return "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; -} - -function isIE9() { - return document.documentMode && document.documentMode <= 9; -} - -// https://github.com/niklasvh/html2canvas/issues/503 -function cloneNodeIE9(node, javascriptEnabled) { - var clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false); - - var child = node.firstChild; - while(child) { - if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') { - clone.appendChild(cloneNodeIE9(child, javascriptEnabled)); - } - child = child.nextSibling; - } - - return clone; -} - -function createWindowClone(ownerDocument, containerDocument, width, height, options, x ,y) { - labelCanvasElements(ownerDocument); - var documentElement = isIE9() ? cloneNodeIE9(ownerDocument.documentElement, options.javascriptEnabled) : ownerDocument.documentElement.cloneNode(true); - var container = containerDocument.createElement("iframe"); - - container.className = "html2canvas-container"; - container.style.visibility = "hidden"; - container.style.position = "fixed"; - container.style.left = "-10000px"; - container.style.top = "0px"; - container.style.border = "0"; - container.width = width; - container.height = height; - container.scrolling = "no"; // ios won't scroll without it - containerDocument.body.appendChild(container); - - return new Promise(function(resolve) { - var documentClone = container.contentWindow.document; - - cloneNodeValues(ownerDocument.documentElement, documentElement, "textarea"); - cloneNodeValues(ownerDocument.documentElement, documentElement, "select"); - - /* Chrome doesn't detect relative background-images assigned in inline ").appendTo(a)),o.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",o.opacity)),o.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",o.zIndex)),this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",t,this._uiHash(this)); +return e.ui.ddmanager&&(e.ui.ddmanager.current=this),e.ui.ddmanager&&!o.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(t),!0},_mouseDrag:function(t){var i,s,n,a,o=this.options,r=!1;for(this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageY=0;i--)if(s=this.items[i],n=s.item[0],a=this._intersectsWithPointer(s),a&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===a?"next":"prev"]()[0]!==n&&!e.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!e.contains(this.element[0],n):!0)){if(this.direction=1===a?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(t,s),this._trigger("change",t,this._uiHash());break}return this._contactContainers(t),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),this._trigger("sort",t,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(t,i){if(t){if(e.ui.ddmanager&&!this.options.dropBehaviour&&e.ui.ddmanager.drop(this,t),this.options.revert){var s=this,n=this.placeholder.offset(),a=this.options.axis,o={};a&&"x"!==a||(o.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollLeft)),a&&"y"!==a||(o.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,e(this.helper).animate(o,parseInt(this.options.revert,10)||500,function(){s._clear(t)})}else this._clear(t,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var t=this.containers.length-1;t>=0;t--)this.containers[t]._trigger("deactivate",null,this._uiHash(this)),this.containers[t].containerCache.over&&(this.containers[t]._trigger("out",null,this._uiHash(this)),this.containers[t].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),e.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?e(this.domPosition.prev).after(this.currentItem):e(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},e(i).each(function(){var i=(e(t.item||this).attr(t.attribute||"id")||"").match(t.expression||/(.+)[\-=_](.+)/);i&&s.push((t.key||i[1]+"[]")+"="+(t.key&&t.expression?i[1]:i[2]))}),!s.length&&t.key&&s.push(t.key+"="),s.join("&")},toArray:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},i.each(function(){s.push(e(t.item||this).attr(t.attribute||"id")||"")}),s},_intersectsWith:function(e){var t=this.positionAbs.left,i=t+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,a=e.left,o=a+e.width,r=e.top,h=r+e.height,l=this.offset.click.top,u=this.offset.click.left,d="x"===this.options.axis||s+l>r&&h>s+l,c="y"===this.options.axis||t+u>a&&o>t+u,p=d&&c;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>e[this.floating?"width":"height"]?p:t+this.helperProportions.width/2>a&&o>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(e){var t="x"===this.options.axis||this._isOverAxis(this.positionAbs.top+this.offset.click.top,e.top,e.height),i="y"===this.options.axis||this._isOverAxis(this.positionAbs.left+this.offset.click.left,e.left,e.width),s=t&&i,n=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return s?this.floating?a&&"right"===a||"down"===n?2:1:n&&("down"===n?2:1):!1},_intersectsWithSides:function(e){var t=this._isOverAxis(this.positionAbs.top+this.offset.click.top,e.top+e.height/2,e.height),i=this._isOverAxis(this.positionAbs.left+this.offset.click.left,e.left+e.width/2,e.width),s=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return this.floating&&n?"right"===n&&i||"left"===n&&!i:s&&("down"===s&&t||"up"===s&&!t)},_getDragVerticalDirection:function(){var e=this.positionAbs.top-this.lastPositionAbs.top;return 0!==e&&(e>0?"down":"up")},_getDragHorizontalDirection:function(){var e=this.positionAbs.left-this.lastPositionAbs.left;return 0!==e&&(e>0?"right":"left")},refresh:function(e){return this._refreshItems(e),this._setHandleClassName(),this.refreshPositions(),this},_connectWith:function(){var e=this.options;return e.connectWith.constructor===String?[e.connectWith]:e.connectWith},_getItemsAsjQuery:function(t){function i(){r.push(this)}var s,n,a,o,r=[],h=[],l=this._connectWith();if(l&&t)for(s=l.length-1;s>=0;s--)for(a=e(l[s],this.document[0]),n=a.length-1;n>=0;n--)o=e.data(a[n],this.widgetFullName),o&&o!==this&&!o.options.disabled&&h.push([e.isFunction(o.options.items)?o.options.items.call(o.element):e(o.options.items,o.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),o]);for(h.push([e.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):e(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=h.length-1;s>=0;s--)h[s][0].each(i);return e(r)},_removeCurrentsFromItems:function(){var t=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=e.grep(this.items,function(e){for(var i=0;t.length>i;i++)if(t[i]===e.item[0])return!1;return!0})},_refreshItems:function(t){this.items=[],this.containers=[this];var i,s,n,a,o,r,h,l,u=this.items,d=[[e.isFunction(this.options.items)?this.options.items.call(this.element[0],t,{item:this.currentItem}):e(this.options.items,this.element),this]],c=this._connectWith();if(c&&this.ready)for(i=c.length-1;i>=0;i--)for(n=e(c[i],this.document[0]),s=n.length-1;s>=0;s--)a=e.data(n[s],this.widgetFullName),a&&a!==this&&!a.options.disabled&&(d.push([e.isFunction(a.options.items)?a.options.items.call(a.element[0],t,{item:this.currentItem}):e(a.options.items,a.element),a]),this.containers.push(a));for(i=d.length-1;i>=0;i--)for(o=d[i][1],r=d[i][0],s=0,l=r.length;l>s;s++)h=e(r[s]),h.data(this.widgetName+"-item",o),u.push({item:h,instance:o,width:0,height:0,left:0,top:0})},refreshPositions:function(t){this.floating=this.items.length?"x"===this.options.axis||this._isFloating(this.items[0].item):!1,this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,a;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?e(this.options.toleranceElement,s.item):s.item,t||(s.width=n.outerWidth(),s.height=n.outerHeight()),a=n.offset(),s.left=a.left,s.top=a.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)a=this.containers[i].element.offset(),this.containers[i].containerCache.left=a.left,this.containers[i].containerCache.top=a.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(t){t=t||this;var i,s=t.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=t.currentItem[0].nodeName.toLowerCase(),n=e("<"+s+">",t.document[0]).addClass(i||t.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tbody"===s?t._createTrPlaceholder(t.currentItem.find("tr").eq(0),e("",t.document[0]).appendTo(n)):"tr"===s?t._createTrPlaceholder(t.currentItem,n):"img"===s&&n.attr("src",t.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(e,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(t.currentItem.innerHeight()-parseInt(t.currentItem.css("paddingTop")||0,10)-parseInt(t.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(t.currentItem.innerWidth()-parseInt(t.currentItem.css("paddingLeft")||0,10)-parseInt(t.currentItem.css("paddingRight")||0,10)))}}),t.placeholder=e(s.placeholder.element.call(t.element,t.currentItem)),t.currentItem.after(t.placeholder),s.placeholder.update(t,t.placeholder)},_createTrPlaceholder:function(t,i){var s=this;t.children().each(function(){e(" ",s.document[0]).attr("colspan",e(this).attr("colspan")||1).appendTo(i)})},_contactContainers:function(t){var i,s,n,a,o,r,h,l,u,d,c=null,p=null;for(i=this.containers.length-1;i>=0;i--)if(!e.contains(this.currentItem[0],this.containers[i].element[0]))if(this._intersectsWith(this.containers[i].containerCache)){if(c&&e.contains(this.containers[i].element[0],c.element[0]))continue;c=this.containers[i],p=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",t,this._uiHash(this)),this.containers[i].containerCache.over=0);if(c)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(n=1e4,a=null,u=c.floating||this._isFloating(this.currentItem),o=u?"left":"top",r=u?"width":"height",d=u?"clientX":"clientY",s=this.items.length-1;s>=0;s--)e.contains(this.containers[p].element[0],this.items[s].item[0])&&this.items[s].item[0]!==this.currentItem[0]&&(h=this.items[s].item.offset()[o],l=!1,t[d]-h>this.items[s][r]/2&&(l=!0),n>Math.abs(t[d]-h)&&(n=Math.abs(t[d]-h),a=this.items[s],this.direction=l?"up":"down"));if(!a&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[p])return this.currentContainer.containerCache.over||(this.containers[p]._trigger("over",t,this._uiHash()),this.currentContainer.containerCache.over=1),void 0;a?this._rearrange(t,a,null,!0):this._rearrange(t,null,this.containers[p].element,!0),this._trigger("change",t,this._uiHash()),this.containers[p]._trigger("change",t,this._uiHash(this)),this.currentContainer=this.containers[p],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1}},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper)?e(i.helper.apply(this.element[0],[t,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||e("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==this.document[0]&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===this.document[0].body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&e.ui.ie)&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var e=this.currentItem.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,"document"===n.containment?this.document.width():this.window.width()-this.helperProportions.width-this.margins.left,("document"===n.containment?this.document.width():this.window.height()||this.document[0].body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(t=e(n.containment)[0],i=e(n.containment).offset(),s="hidden"!==e(t).css("overflow"),this.containment=[i.left+(parseInt(e(t).css("borderLeftWidth"),10)||0)+(parseInt(e(t).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(e(t).css("borderTopWidth"),10)||0)+(parseInt(e(t).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(t.scrollWidth,t.offsetWidth):t.offsetWidth)-(parseInt(e(t).css("borderLeftWidth"),10)||0)-(parseInt(e(t).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(t.scrollHeight,t.offsetHeight):t.offsetHeight)-(parseInt(e(t).css("borderTopWidth"),10)||0)-(parseInt(e(t).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(t,i){i||(i=this.position);var s="absolute"===t?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,a=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():a?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():a?0:n.scrollLeft())*s}},_generatePosition:function(t){var i,s,n=this.options,a=t.pageX,o=t.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(t.pageX-this.offset.click.leftthis.containment[2]&&(a=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(o=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1],o=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((a-this.originalPageX)/n.grid[0])*n.grid[0],a=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:o-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:a-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(e,t,i,s){i?i[0].appendChild(this.placeholder[0]):t.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?t.item[0]:t.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(e,t){function i(e,t,i){return function(s){i._trigger(e,s,t._uiHash(t))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!t&&n.push(function(e){this._trigger("receive",e,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||t||n.push(function(e){this._trigger("update",e,this._uiHash())}),this!==this.currentContainer&&(t||(n.push(function(e){this._trigger("remove",e,this._uiHash())}),n.push(function(e){return function(t){e._trigger("receive",t,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(e){return function(t){e._trigger("update",t,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)t||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,t||this._trigger("beforeStop",e,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!t){for(s=0;n.length>s;s++)n[s].call(this,e);this._trigger("stop",e,this._uiHash())}return this.fromOutside=!1,!this.cancelHelperRemoval},_trigger:function(){e.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(t){var i=t||this;return{helper:i.helper,placeholder:i.placeholder||e([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:t?t.element:null}}}),e.widget("ui.spinner",{version:"1.11.4",defaultElement:"",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var t={},i=this.element;return e.each(["min","max","step"],function(e,s){var n=i.attr(s);void 0!==n&&n.length&&(t[s]=n)}),t},_events:{keydown:function(e){this._start(e)&&this._keydown(e)&&e.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(e){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",e),void 0)},mousewheel:function(e,t){if(t){if(!this.spinning&&!this._start(e))return!1;this._spin((t>0?1:-1)*this.options.step,e),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(e)},100),e.preventDefault()}},"mousedown .ui-spinner-button":function(t){function i(){var e=this.element[0]===this.document[0].activeElement;e||(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),t.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(t)!==!1&&this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(t){return e(t.currentTarget).hasClass("ui-state-active")?this._start(t)===!1?!1:(this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var e=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=e.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(.5*e.height())&&e.height()>0&&e.height(e.height()),this.options.disabled&&this.disable()},_keydown:function(t){var i=this.options,s=e.ui.keyCode;switch(t.keyCode){case s.UP:return this._repeat(null,1,t),!0;case s.DOWN:return this._repeat(null,-1,t),!0;case s.PAGE_UP:return this._repeat(null,i.page,t),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,t),!0}return!1},_uiSpinnerHtml:function(){return""},_buttonHtml:function(){return"
"+""+""+""+""},_start:function(e){return this.spinning||this._trigger("start",e)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(e,t,i){e=e||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,t,i)},e),this._spin(t*this.options.step,i)},_spin:function(e,t){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+e*this._increment(this.counter)),this.spinning&&this._trigger("spin",t,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(t){var i=this.options.incremental;return i?e.isFunction(i)?i(t):Math.floor(t*t*t/5e4-t*t/500+17*t/200+1):1},_precision:function(){var e=this._precisionOf(this.options.step);return null!==this.options.min&&(e=Math.max(e,this._precisionOf(this.options.min))),e},_precisionOf:function(e){var t=""+e,i=t.indexOf(".");return-1===i?0:t.length-i-1},_adjustValue:function(e){var t,i,s=this.options;return t=null!==s.min?s.min:0,i=e-t,i=Math.round(i/s.step)*s.step,e=t+i,e=parseFloat(e.toFixed(this._precision())),null!==s.max&&e>s.max?s.max:null!==s.min&&s.min>e?s.min:e},_stop:function(e){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",e))},_setOption:function(e,t){if("culture"===e||"numberFormat"===e){var i=this._parse(this.element.val());return this.options[e]=t,this.element.val(this._format(i)),void 0}("max"===e||"min"===e||"step"===e)&&"string"==typeof t&&(t=this._parse(t)),"icons"===e&&(this.buttons.first().find(".ui-icon").removeClass(this.options.icons.up).addClass(t.up),this.buttons.last().find(".ui-icon").removeClass(this.options.icons.down).addClass(t.down)),this._super(e,t),"disabled"===e&&(this.widget().toggleClass("ui-state-disabled",!!t),this.element.prop("disabled",!!t),this.buttons.button(t?"disable":"enable"))},_setOptions:h(function(e){this._super(e)}),_parse:function(e){return"string"==typeof e&&""!==e&&(e=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(e,10,this.options.culture):+e),""===e||isNaN(e)?null:e},_format:function(e){return""===e?"":window.Globalize&&this.options.numberFormat?Globalize.format(e,this.options.numberFormat,this.options.culture):e},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},isValid:function(){var e=this.value();return null===e?!1:e===this._adjustValue(e)},_value:function(e,t){var i;""!==e&&(i=this._parse(e),null!==i&&(t||(i=this._adjustValue(i)),e=this._format(i))),this.element.val(e),this._refresh()},_destroy:function(){this.element.removeClass("ui-spinner-input").prop("disabled",!1).removeAttr("autocomplete").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:h(function(e){this._stepUp(e)}),_stepUp:function(e){this._start()&&(this._spin((e||1)*this.options.step),this._stop())},stepDown:h(function(e){this._stepDown(e)}),_stepDown:function(e){this._start()&&(this._spin((e||1)*-this.options.step),this._stop())},pageUp:h(function(e){this._stepUp((e||1)*this.options.page)}),pageDown:h(function(e){this._stepDown((e||1)*this.options.page)}),value:function(e){return arguments.length?(h(this._value).call(this,e),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}}),e.widget("ui.tabs",{version:"1.11.4",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_isLocal:function(){var e=/#.*$/;return function(t){var i,s;t=t.cloneNode(!1),i=t.href.replace(e,""),s=location.href.replace(e,"");try{i=decodeURIComponent(i)}catch(n){}try{s=decodeURIComponent(s)}catch(n){}return t.hash.length>1&&i===s}}(),_create:function(){var t=this,i=this.options;this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",i.collapsible),this._processTabs(),i.active=this._initialActive(),e.isArray(i.disabled)&&(i.disabled=e.unique(i.disabled.concat(e.map(this.tabs.filter(".ui-state-disabled"),function(e){return t.tabs.index(e)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):e(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var t=this.options.active,i=this.options.collapsible,s=location.hash.substring(1);return null===t&&(s&&this.tabs.each(function(i,n){return e(n).attr("aria-controls")===s?(t=i,!1):void 0}),null===t&&(t=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===t||-1===t)&&(t=this.tabs.length?0:!1)),t!==!1&&(t=this.tabs.index(this.tabs.eq(t)),-1===t&&(t=i?!1:0)),!i&&t===!1&&this.anchors.length&&(t=0),t},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):e()}},_tabKeydown:function(t){var i=e(this.document[0].activeElement).closest("li"),s=this.tabs.index(i),n=!0;if(!this._handlePageNav(t)){switch(t.keyCode){case e.ui.keyCode.RIGHT:case e.ui.keyCode.DOWN:s++;break;case e.ui.keyCode.UP:case e.ui.keyCode.LEFT:n=!1,s--;break;case e.ui.keyCode.END:s=this.anchors.length-1;break;case e.ui.keyCode.HOME:s=0;break;case e.ui.keyCode.SPACE:return t.preventDefault(),clearTimeout(this.activating),this._activate(s),void 0;case e.ui.keyCode.ENTER:return t.preventDefault(),clearTimeout(this.activating),this._activate(s===this.options.active?!1:s),void 0;default:return}t.preventDefault(),clearTimeout(this.activating),s=this._focusNextTab(s,n),t.ctrlKey||t.metaKey||(i.attr("aria-selected","false"),this.tabs.eq(s).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",s)},this.delay))}},_panelKeydown:function(t){this._handlePageNav(t)||t.ctrlKey&&t.keyCode===e.ui.keyCode.UP&&(t.preventDefault(),this.active.focus())},_handlePageNav:function(t){return t.altKey&&t.keyCode===e.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):t.altKey&&t.keyCode===e.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):void 0},_findNextTab:function(t,i){function s(){return t>n&&(t=0),0>t&&(t=n),t}for(var n=this.tabs.length-1;-1!==e.inArray(s(),this.options.disabled);)t=i?t+1:t-1;return t},_focusNextTab:function(e,t){return e=this._findNextTab(e,t),this.tabs.eq(e).focus(),e},_setOption:function(e,t){return"active"===e?(this._activate(t),void 0):"disabled"===e?(this._setupDisabled(t),void 0):(this._super(e,t),"collapsible"===e&&(this.element.toggleClass("ui-tabs-collapsible",t),t||this.options.active!==!1||this._activate(0)),"event"===e&&this._setupEvents(t),"heightStyle"===e&&this._setupHeightStyle(t),void 0)},_sanitizeSelector:function(e){return e?e.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var t=this.options,i=this.tablist.children(":has(a[href])");t.disabled=e.map(i.filter(".ui-state-disabled"),function(e){return i.index(e)}),this._processTabs(),t.active!==!1&&this.anchors.length?this.active.length&&!e.contains(this.tablist[0],this.active[0])?this.tabs.length===t.disabled.length?(t.active=!1,this.active=e()):this._activate(this._findNextTab(Math.max(0,t.active-1),!1)):t.active=this.tabs.index(this.active):(t.active=!1,this.active=e()),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var t=this,i=this.tabs,s=this.anchors,n=this.panels; +this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist").delegate("> li","mousedown"+this.eventNamespace,function(t){e(this).is(".ui-state-disabled")&&t.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){e(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return e("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=e(),this.anchors.each(function(i,s){var n,a,o,r=e(s).uniqueId().attr("id"),h=e(s).closest("li"),l=h.attr("aria-controls");t._isLocal(s)?(n=s.hash,o=n.substring(1),a=t.element.find(t._sanitizeSelector(n))):(o=h.attr("aria-controls")||e({}).uniqueId()[0].id,n="#"+o,a=t.element.find(n),a.length||(a=t._createPanel(o),a.insertAfter(t.panels[i-1]||t.tablist)),a.attr("aria-live","polite")),a.length&&(t.panels=t.panels.add(a)),l&&h.data("ui-tabs-aria-controls",l),h.attr({"aria-controls":o,"aria-labelledby":r}),a.attr("aria-labelledby",r)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel"),i&&(this._off(i.not(this.tabs)),this._off(s.not(this.anchors)),this._off(n.not(this.panels)))},_getList:function(){return this.tablist||this.element.find("ol,ul").eq(0)},_createPanel:function(t){return e("
").attr("id",t).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(t){e.isArray(t)&&(t.length?t.length===this.anchors.length&&(t=!0):t=!1);for(var i,s=0;i=this.tabs[s];s++)t===!0||-1!==e.inArray(s,t)?e(i).addClass("ui-state-disabled").attr("aria-disabled","true"):e(i).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=t},_setupEvents:function(t){var i={};t&&e.each(t.split(" "),function(e,t){i[t]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(!0,this.anchors,{click:function(e){e.preventDefault()}}),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(t){var i,s=this.element.parent();"fill"===t?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var t=e(this),s=t.css("position");"absolute"!==s&&"fixed"!==s&&(i-=t.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=e(this).outerHeight(!0)}),this.panels.each(function(){e(this).height(Math.max(0,i-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):"auto"===t&&(i=0,this.panels.each(function(){i=Math.max(i,e(this).height("").height())}).height(i))},_eventHandler:function(t){var i=this.options,s=this.active,n=e(t.currentTarget),a=n.closest("li"),o=a[0]===s[0],r=o&&i.collapsible,h=r?e():this._getPanelForTab(a),l=s.length?this._getPanelForTab(s):e(),u={oldTab:s,oldPanel:l,newTab:r?e():a,newPanel:h};t.preventDefault(),a.hasClass("ui-state-disabled")||a.hasClass("ui-tabs-loading")||this.running||o&&!i.collapsible||this._trigger("beforeActivate",t,u)===!1||(i.active=r?!1:this.tabs.index(a),this.active=o?e():a,this.xhr&&this.xhr.abort(),l.length||h.length||e.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(a),t),this._toggle(t,u))},_toggle:function(t,i){function s(){a.running=!1,a._trigger("activate",t,i)}function n(){i.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),o.length&&a.options.show?a._show(o,a.options.show,s):(o.show(),s())}var a=this,o=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),n()}):(i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),r.hide(),n()),r.attr("aria-hidden","true"),i.oldTab.attr({"aria-selected":"false","aria-expanded":"false"}),o.length&&r.length?i.oldTab.attr("tabIndex",-1):o.length&&this.tabs.filter(function(){return 0===e(this).attr("tabIndex")}).attr("tabIndex",-1),o.attr("aria-hidden","false"),i.newTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_activate:function(t){var i,s=this._findActive(t);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:e.noop}))},_findActive:function(t){return t===!1?e():this.tabs.eq(t)},_getIndex:function(e){return"string"==typeof e&&(e=this.anchors.index(this.anchors.filter("[href$='"+e+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tablist.unbind(this.eventNamespace),this.tabs.add(this.panels).each(function(){e.data(this,"ui-tabs-destroy")?e(this).remove():e(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var t=e(this),i=t.data("ui-tabs-aria-controls");i?t.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):t.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(t){var i=this.options.disabled;i!==!1&&(void 0===t?i=!1:(t=this._getIndex(t),i=e.isArray(i)?e.map(i,function(e){return e!==t?e:null}):e.map(this.tabs,function(e,i){return i!==t?i:null})),this._setupDisabled(i))},disable:function(t){var i=this.options.disabled;if(i!==!0){if(void 0===t)i=!0;else{if(t=this._getIndex(t),-1!==e.inArray(t,i))return;i=e.isArray(i)?e.merge([t],i).sort():[t]}this._setupDisabled(i)}},load:function(t,i){t=this._getIndex(t);var s=this,n=this.tabs.eq(t),a=n.find(".ui-tabs-anchor"),o=this._getPanelForTab(n),r={tab:n,panel:o},h=function(e,t){"abort"===t&&s.panels.stop(!1,!0),n.removeClass("ui-tabs-loading"),o.removeAttr("aria-busy"),e===s.xhr&&delete s.xhr};this._isLocal(a[0])||(this.xhr=e.ajax(this._ajaxSettings(a,i,r)),this.xhr&&"canceled"!==this.xhr.statusText&&(n.addClass("ui-tabs-loading"),o.attr("aria-busy","true"),this.xhr.done(function(e,t,n){setTimeout(function(){o.html(e),s._trigger("load",i,r),h(n,t)},1)}).fail(function(e,t){setTimeout(function(){h(e,t)},1)})))},_ajaxSettings:function(t,i,s){var n=this;return{url:t.attr("href"),beforeSend:function(t,a){return n._trigger("beforeLoad",i,e.extend({jqXHR:t,ajaxSettings:a},s))}}},_getPanelForTab:function(t){var i=e(t).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}}),e.widget("ui.tooltip",{version:"1.11.4",options:{content:function(){var t=e(this).attr("title")||"";return e("").text(t).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_addDescribedBy:function(t,i){var s=(t.attr("aria-describedby")||"").split(/\s+/);s.push(i),t.data("ui-tooltip-id",i).attr("aria-describedby",e.trim(s.join(" ")))},_removeDescribedBy:function(t){var i=t.data("ui-tooltip-id"),s=(t.attr("aria-describedby")||"").split(/\s+/),n=e.inArray(i,s);-1!==n&&s.splice(n,1),t.removeData("ui-tooltip-id"),s=e.trim(s.join(" ")),s?t.attr("aria-describedby",s):t.removeAttr("aria-describedby")},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable(),this.liveRegion=e("
").attr({role:"log","aria-live":"assertive","aria-relevant":"additions"}).addClass("ui-helper-hidden-accessible").appendTo(this.document[0].body)},_setOption:function(t,i){var s=this;return"disabled"===t?(this[i?"_disable":"_enable"](),this.options[t]=i,void 0):(this._super(t,i),"content"===t&&e.each(this.tooltips,function(e,t){s._updateContent(t.element)}),void 0)},_disable:function(){var t=this;e.each(this.tooltips,function(i,s){var n=e.Event("blur");n.target=n.currentTarget=s.element[0],t.close(n,!0)}),this.element.find(this.options.items).addBack().each(function(){var t=e(this);t.is("[title]")&&t.data("ui-tooltip-title",t.attr("title")).removeAttr("title")})},_enable:function(){this.element.find(this.options.items).addBack().each(function(){var t=e(this);t.data("ui-tooltip-title")&&t.attr("title",t.data("ui-tooltip-title"))})},open:function(t){var i=this,s=e(t?t.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),t&&"mouseover"===t.type&&s.parents().each(function(){var t,s=e(this);s.data("ui-tooltip-open")&&(t=e.Event("blur"),t.target=t.currentTarget=this,i.close(t,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._registerCloseHandlers(t,s),this._updateContent(s,t))},_updateContent:function(e,t){var i,s=this.options.content,n=this,a=t?t.type:null;return"string"==typeof s?this._open(t,e,s):(i=s.call(e[0],function(i){n._delay(function(){e.data("ui-tooltip-open")&&(t&&(t.type=a),this._open(t,e,i))})}),i&&this._open(t,e,i),void 0)},_open:function(t,i,s){function n(e){l.of=e,o.is(":hidden")||o.position(l)}var a,o,r,h,l=e.extend({},this.options.position);if(s){if(a=this._find(i))return a.tooltip.find(".ui-tooltip-content").html(s),void 0;i.is("[title]")&&(t&&"mouseover"===t.type?i.attr("title",""):i.removeAttr("title")),a=this._tooltip(i),o=a.tooltip,this._addDescribedBy(i,o.attr("id")),o.find(".ui-tooltip-content").html(s),this.liveRegion.children().hide(),s.clone?(h=s.clone(),h.removeAttr("id").find("[id]").removeAttr("id")):h=s,e("
").html(h).appendTo(this.liveRegion),this.options.track&&t&&/^mouse/.test(t.type)?(this._on(this.document,{mousemove:n}),n(t)):o.position(e.extend({of:i},this.options.position)),o.hide(),this._show(o,this.options.show),this.options.show&&this.options.show.delay&&(r=this.delayedShow=setInterval(function(){o.is(":visible")&&(n(l.of),clearInterval(r))},e.fx.interval)),this._trigger("open",t,{tooltip:o})}},_registerCloseHandlers:function(t,i){var s={keyup:function(t){if(t.keyCode===e.ui.keyCode.ESCAPE){var s=e.Event(t);s.currentTarget=i[0],this.close(s,!0)}}};i[0]!==this.element[0]&&(s.remove=function(){this._removeTooltip(this._find(i).tooltip)}),t&&"mouseover"!==t.type||(s.mouseleave="close"),t&&"focusin"!==t.type||(s.focusout="close"),this._on(!0,i,s)},close:function(t){var i,s=this,n=e(t?t.currentTarget:this.element),a=this._find(n);return a?(i=a.tooltip,a.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&!n.attr("title")&&n.attr("title",n.data("ui-tooltip-title")),this._removeDescribedBy(n),a.hiding=!0,i.stop(!0),this._hide(i,this.options.hide,function(){s._removeTooltip(e(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),t&&"mouseleave"===t.type&&e.each(this.parents,function(t,i){e(i.element).attr("title",i.title),delete s.parents[t]}),a.closing=!0,this._trigger("close",t,{tooltip:i}),a.hiding||(a.closing=!1)),void 0):(n.removeData("ui-tooltip-open"),void 0)},_tooltip:function(t){var i=e("
").attr("role","tooltip").addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||"")),s=i.uniqueId().attr("id");return e("
").addClass("ui-tooltip-content").appendTo(i),i.appendTo(this.document[0].body),this.tooltips[s]={element:t,tooltip:i}},_find:function(e){var t=e.data("ui-tooltip-id");return t?this.tooltips[t]:null},_removeTooltip:function(e){e.remove(),delete this.tooltips[e.attr("id")]},_destroy:function(){var t=this;e.each(this.tooltips,function(i,s){var n=e.Event("blur"),a=s.element;n.target=n.currentTarget=a[0],t.close(n,!0),e("#"+i).remove(),a.data("ui-tooltip-title")&&(a.attr("title")||a.attr("title",a.data("ui-tooltip-title")),a.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}})}); \ No newline at end of file diff --git a/content/lib/nouislider.css b/content/lib/nouislider.css deleted file mode 100644 index 517ec621..00000000 --- a/content/lib/nouislider.css +++ /dev/null @@ -1,162 +0,0 @@ - -/* Functional styling; - * These styles are required for noUiSlider to function. - * You don't need to change these rules to apply your design. - */ -.noUi-target, -.noUi-target * { --webkit-touch-callout: none; --webkit-user-select: none; --ms-touch-action: none; --ms-user-select: none; --moz-user-select: none; --moz-box-sizing: border-box; - box-sizing: border-box; -} -.noUi-target { - position: relative; - direction: ltr; -} -.noUi-base { - width: 100%; - height: 100%; - position: relative; - z-index: 1; /* Fix 401 */ -} -.noUi-origin { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; -} -.noUi-handle { - position: relative; - z-index: 1; -} -.noUi-stacking .noUi-handle { -/* This class is applied to the lower origin when - its values is > 50%. */ - z-index: 10; -} -.noUi-state-tap .noUi-origin { --webkit-transition: left 0.3s, top 0.3s; - transition: left 0.3s, top 0.3s; -} -.noUi-state-drag * { - cursor: inherit !important; -} - -/* Painting and performance; - * Browsers can paint handles in their own layer. - */ -.noUi-base { - -webkit-transform: translate3d(0,0,0); - transform: translate3d(0,0,0); -} - -/* Slider size and handle placement; - */ -.noUi-horizontal { - height: 18px; -} -.noUi-horizontal .noUi-handle { - width: 34px; - height: 28px; - left: -17px; - top: -6px; -} -.noUi-vertical { - width: 18px; -} -.noUi-vertical .noUi-handle { - width: 28px; - height: 34px; - left: -6px; - top: -17px; -} - -/* Styling; - */ -.noUi-background { - background: #FAFAFA; - box-shadow: inset 0 1px 1px #f0f0f0; -} -.noUi-connect { - background: #3FB8AF; - box-shadow: inset 0 0 3px rgba(51,51,51,0.45); --webkit-transition: background 450ms; - transition: background 450ms; -} -.noUi-origin { - border-radius: 2px; -} -.noUi-target { - border-radius: 4px; - border: 1px solid #D3D3D3; - box-shadow: inset 0 1px 1px #F0F0F0, 0 3px 6px -5px #BBB; -} -.noUi-target.noUi-connect { - box-shadow: inset 0 0 3px rgba(51,51,51,0.45), 0 3px 6px -5px #BBB; -} - -/* Handles and cursors; - */ -.noUi-dragable { - cursor: w-resize; -} -.noUi-vertical .noUi-dragable { - cursor: n-resize; -} -.noUi-handle { - border: 1px solid #D9D9D9; - border-radius: 3px; - background: #FFF; - cursor: default; - box-shadow: inset 0 0 1px #FFF, - inset 0 1px 7px #EBEBEB, - 0 3px 6px -3px #BBB; -} -.noUi-active { - box-shadow: inset 0 0 1px #FFF, - inset 0 1px 7px #DDD, - 0 3px 6px -3px #BBB; -} - -/* Handle stripes; - */ -.noUi-handle:before, -.noUi-handle:after { - content: ""; - display: block; - position: absolute; - height: 14px; - width: 1px; - background: #E8E7E6; - left: 14px; - top: 6px; -} -.noUi-handle:after { - left: 17px; -} -.noUi-vertical .noUi-handle:before, -.noUi-vertical .noUi-handle:after { - width: 14px; - height: 1px; - left: 6px; - top: 14px; -} -.noUi-vertical .noUi-handle:after { - top: 17px; -} - -/* Disabled state; - */ -[disabled].noUi-connect, -[disabled] .noUi-connect { - background: #B8B8B8; -} -[disabled].noUi-origin, -[disabled] .noUi-handle { - cursor: not-allowed; -} diff --git a/content/lib/nouislider.js b/content/lib/nouislider.js deleted file mode 100644 index 67ae7549..00000000 --- a/content/lib/nouislider.js +++ /dev/null @@ -1,1629 +0,0 @@ -/*! nouislider - 8.0.2 - 2015-07-06 13:22:09 */ - -/*jslint browser: true */ -/*jslint white: true */ - -(function (factory) { - - if ( typeof define === 'function' && define.amd ) { - - // AMD. Register as an anonymous module. - define([], factory); - - } else if ( typeof exports === 'object' ) { - - var fs = require('fs'); - - // Node/CommonJS - module.exports = factory(); - module.exports.css = function () { - return fs.readFileSync(__dirname + '/nouislider.min.css', 'utf8'); - }; - - } else { - - // Browser globals - window.noUiSlider = factory(); - } - -}(function( ){ - - 'use strict'; - - - // Removes duplicates from an array. - function unique(array) { - return array.filter(function(a){ - return !this[a] ? this[a] = true : false; - }, {}); - } - - // Round a value to the closest 'to'. - function closest ( value, to ) { - return Math.round(value / to) * to; - } - - // Current position of an element relative to the document. - function offset ( elem ) { - - var rect = elem.getBoundingClientRect(), - doc = elem.ownerDocument, - win = doc.defaultView || doc.parentWindow, - docElem = doc.documentElement, - xOff = win.pageXOffset; - - // getBoundingClientRect contains left scroll in Chrome on Android. - // I haven't found a feature detection that proves this. Worst case - // scenario on mis-match: the 'tap' feature on horizontal sliders breaks. - if ( /webkit.*Chrome.*Mobile/i.test(navigator.userAgent) ) { - xOff = 0; - } - - return { - top: rect.top + win.pageYOffset - docElem.clientTop, - left: rect.left + xOff - docElem.clientLeft - }; - } - - // Checks whether a value is numerical. - function isNumeric ( a ) { - return typeof a === 'number' && !isNaN( a ) && isFinite( a ); - } - - // Rounds a number to 7 supported decimals. - function accurateNumber( number ) { - var p = Math.pow(10, 7); - return Number((Math.round(number*p)/p).toFixed(7)); - } - - // Sets a class and removes it after [duration] ms. - function addClassFor ( element, className, duration ) { - addClass(element, className); - setTimeout(function(){ - removeClass(element, className); - }, duration); - } - - // Limits a value to 0 - 100 - function limit ( a ) { - return Math.max(Math.min(a, 100), 0); - } - - // Wraps a variable as an array, if it isn't one yet. - function asArray ( a ) { - return Array.isArray(a) ? a : [a]; - } - - // Counts decimals - function countDecimals ( numStr ) { - var pieces = numStr.split("."); - return pieces.length > 1 ? pieces[1].length : 0; - } - - // http://youmightnotneedjquery.com/#add_class - function addClass ( el, className ) { - if ( el.classList ) { - el.classList.add(className); - } else { - el.className += ' ' + className; - } - } - - // http://youmightnotneedjquery.com/#remove_class - function removeClass ( el, className ) { - if ( el.classList ) { - el.classList.remove(className); - } else { - el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); - } - } - - // http://youmightnotneedjquery.com/#has_class - function hasClass ( el, className ) { - if ( el.classList ) { - el.classList.contains(className); - } else { - new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className); - } - } - - - var - // Determine the events to bind. IE11 implements pointerEvents without - // a prefix, which breaks compatibility with the IE10 implementation. - /** @const */ - actions = window.navigator.pointerEnabled ? { - start: 'pointerdown', - move: 'pointermove', - end: 'pointerup' - } : window.navigator.msPointerEnabled ? { - start: 'MSPointerDown', - move: 'MSPointerMove', - end: 'MSPointerUp' - } : { - start: 'mousedown touchstart', - move: 'mousemove touchmove', - end: 'mouseup touchend' - }, - // Re-usable list of classes; - /** @const */ - Classes = [ -/* 0 */ 'noUi-target' -/* 1 */ ,'noUi-base' -/* 2 */ ,'noUi-origin' -/* 3 */ ,'noUi-handle' -/* 4 */ ,'noUi-horizontal' -/* 5 */ ,'noUi-vertical' -/* 6 */ ,'noUi-background' -/* 7 */ ,'noUi-connect' -/* 8 */ ,'noUi-ltr' -/* 9 */ ,'noUi-rtl' -/* 10 */ ,'noUi-dragable' -/* 11 */ ,'' -/* 12 */ ,'noUi-state-drag' -/* 13 */ ,'' -/* 14 */ ,'noUi-state-tap' -/* 15 */ ,'noUi-active' -/* 16 */ ,'' -/* 17 */ ,'noUi-stacking' - ]; - - -// Value calculation - - // Determine the size of a sub-range in relation to a full range. - function subRangeRatio ( pa, pb ) { - return (100 / (pb - pa)); - } - - // (percentage) How many percent is this value of this range? - function fromPercentage ( range, value ) { - return (value * 100) / ( range[1] - range[0] ); - } - - // (percentage) Where is this value on this range? - function toPercentage ( range, value ) { - return fromPercentage( range, range[0] < 0 ? - value + Math.abs(range[0]) : - value - range[0] ); - } - - // (value) How much is this percentage on this range? - function isPercentage ( range, value ) { - return ((value * ( range[1] - range[0] )) / 100) + range[0]; - } - - -// Range conversion - - function getJ ( value, arr ) { - - var j = 1; - - while ( value >= arr[j] ){ - j += 1; - } - - return j; - } - - // (percentage) Input a value, find where, on a scale of 0-100, it applies. - function toStepping ( xVal, xPct, value ) { - - if ( value >= xVal.slice(-1)[0] ){ - return 100; - } - - var j = getJ( value, xVal ), va, vb, pa, pb; - - va = xVal[j-1]; - vb = xVal[j]; - pa = xPct[j-1]; - pb = xPct[j]; - - return pa + (toPercentage([va, vb], value) / subRangeRatio (pa, pb)); - } - - // (value) Input a percentage, find where it is on the specified range. - function fromStepping ( xVal, xPct, value ) { - - // There is no range group that fits 100 - if ( value >= 100 ){ - return xVal.slice(-1)[0]; - } - - var j = getJ( value, xPct ), va, vb, pa, pb; - - va = xVal[j-1]; - vb = xVal[j]; - pa = xPct[j-1]; - pb = xPct[j]; - - return isPercentage([va, vb], (value - pa) * subRangeRatio (pa, pb)); - } - - // (percentage) Get the step that applies at a certain value. - function getStep ( xPct, xSteps, snap, value ) { - - if ( value === 100 ) { - return value; - } - - var j = getJ( value, xPct ), a, b; - - // If 'snap' is set, steps are used as fixed points on the slider. - if ( snap ) { - - a = xPct[j-1]; - b = xPct[j]; - - // Find the closest position, a or b. - if ((value - a) > ((b-a)/2)){ - return b; - } - - return a; - } - - if ( !xSteps[j-1] ){ - return value; - } - - return xPct[j-1] + closest( - value - xPct[j-1], - xSteps[j-1] - ); - } - - -// Entry parsing - - function handleEntryPoint ( index, value, that ) { - - var percentage; - - // Wrap numerical input in an array. - if ( typeof value === "number" ) { - value = [value]; - } - - // Reject any invalid input, by testing whether value is an array. - if ( Object.prototype.toString.call( value ) !== '[object Array]' ){ - throw new Error("noUiSlider: 'range' contains invalid value."); - } - - // Covert min/max syntax to 0 and 100. - if ( index === 'min' ) { - percentage = 0; - } else if ( index === 'max' ) { - percentage = 100; - } else { - percentage = parseFloat( index ); - } - - // Check for correct input. - if ( !isNumeric( percentage ) || !isNumeric( value[0] ) ) { - throw new Error("noUiSlider: 'range' value isn't numeric."); - } - - // Store values. - that.xPct.push( percentage ); - that.xVal.push( value[0] ); - - // NaN will evaluate to false too, but to keep - // logging clear, set step explicitly. Make sure - // not to override the 'step' setting with false. - if ( !percentage ) { - if ( !isNaN( value[1] ) ) { - that.xSteps[0] = value[1]; - } - } else { - that.xSteps.push( isNaN(value[1]) ? false : value[1] ); - } - } - - function handleStepPoint ( i, n, that ) { - - // Ignore 'false' stepping. - if ( !n ) { - return true; - } - - // Factor to range ratio - that.xSteps[i] = fromPercentage([ - that.xVal[i] - ,that.xVal[i+1] - ], n) / subRangeRatio ( - that.xPct[i], - that.xPct[i+1] ); - } - - -// Interface - - // The interface to Spectrum handles all direction-based - // conversions, so the above values are unaware. - - function Spectrum ( entry, snap, direction, singleStep ) { - - this.xPct = []; - this.xVal = []; - this.xSteps = [ singleStep || false ]; - this.xNumSteps = [ false ]; - - this.snap = snap; - this.direction = direction; - - var index, ordered = [ /* [0, 'min'], [1, '50%'], [2, 'max'] */ ]; - - // Map the object keys to an array. - for ( index in entry ) { - if ( entry.hasOwnProperty(index) ) { - ordered.push([entry[index], index]); - } - } - - // Sort all entries by value (numeric sort). - ordered.sort(function(a, b) { return a[0] - b[0]; }); - - // Convert all entries to subranges. - for ( index = 0; index < ordered.length; index++ ) { - handleEntryPoint(ordered[index][1], ordered[index][0], this); - } - - // Store the actual step values. - // xSteps is sorted in the same order as xPct and xVal. - this.xNumSteps = this.xSteps.slice(0); - - // Convert all numeric steps to the percentage of the subrange they represent. - for ( index = 0; index < this.xNumSteps.length; index++ ) { - handleStepPoint(index, this.xNumSteps[index], this); - } - } - - Spectrum.prototype.getMargin = function ( value ) { - return this.xPct.length === 2 ? fromPercentage(this.xVal, value) : false; - }; - - Spectrum.prototype.toStepping = function ( value ) { - - value = toStepping( this.xVal, this.xPct, value ); - - // Invert the value if this is a right-to-left slider. - if ( this.direction ) { - value = 100 - value; - } - - return value; - }; - - Spectrum.prototype.fromStepping = function ( value ) { - - // Invert the value if this is a right-to-left slider. - if ( this.direction ) { - value = 100 - value; - } - - return accurateNumber(fromStepping( this.xVal, this.xPct, value )); - }; - - Spectrum.prototype.getStep = function ( value ) { - - // Find the proper step for rtl sliders by search in inverse direction. - // Fixes issue #262. - if ( this.direction ) { - value = 100 - value; - } - - value = getStep(this.xPct, this.xSteps, this.snap, value ); - - if ( this.direction ) { - value = 100 - value; - } - - return value; - }; - - Spectrum.prototype.getApplicableStep = function ( value ) { - - // If the value is 100%, return the negative step twice. - var j = getJ(value, this.xPct), offset = value === 100 ? 2 : 1; - return [this.xNumSteps[j-2], this.xVal[j-offset], this.xNumSteps[j-offset]]; - }; - - // Outside testing - Spectrum.prototype.convert = function ( value ) { - return this.getStep(this.toStepping(value)); - }; - -/* Every input option is tested and parsed. This'll prevent - endless validation in internal methods. These tests are - structured with an item for every option available. An - option can be marked as required by setting the 'r' flag. - The testing function is provided with three arguments: - - The provided value for the option; - - A reference to the options object; - - The name for the option; - - The testing function returns false when an error is detected, - or true when everything is OK. It can also modify the option - object, to make sure all values can be correctly looped elsewhere. */ - - var defaultFormatter = { 'to': function( value ){ - return value.toFixed(2); - }, 'from': Number }; - - function testStep ( parsed, entry ) { - - if ( !isNumeric( entry ) ) { - throw new Error("noUiSlider: 'step' is not numeric."); - } - - // The step option can still be used to set stepping - // for linear sliders. Overwritten if set in 'range'. - parsed.singleStep = entry; - } - - function testRange ( parsed, entry ) { - - // Filter incorrect input. - if ( typeof entry !== 'object' || Array.isArray(entry) ) { - throw new Error("noUiSlider: 'range' is not an object."); - } - - // Catch missing start or end. - if ( entry.min === undefined || entry.max === undefined ) { - throw new Error("noUiSlider: Missing 'min' or 'max' in 'range'."); - } - - parsed.spectrum = new Spectrum(entry, parsed.snap, parsed.dir, parsed.singleStep); - } - - function testStart ( parsed, entry ) { - - entry = asArray(entry); - - // Validate input. Values aren't tested, as the public .val method - // will always provide a valid location. - if ( !Array.isArray( entry ) || !entry.length || entry.length > 2 ) { - throw new Error("noUiSlider: 'start' option is incorrect."); - } - - // Store the number of handles. - parsed.handles = entry.length; - - // When the slider is initialized, the .val method will - // be called with the start options. - parsed.start = entry; - } - - function testSnap ( parsed, entry ) { - - // Enforce 100% stepping within subranges. - parsed.snap = entry; - - if ( typeof entry !== 'boolean' ){ - throw new Error("noUiSlider: 'snap' option must be a boolean."); - } - } - - function testAnimate ( parsed, entry ) { - - // Enforce 100% stepping within subranges. - parsed.animate = entry; - - if ( typeof entry !== 'boolean' ){ - throw new Error("noUiSlider: 'animate' option must be a boolean."); - } - } - - function testConnect ( parsed, entry ) { - - if ( entry === 'lower' && parsed.handles === 1 ) { - parsed.connect = 1; - } else if ( entry === 'upper' && parsed.handles === 1 ) { - parsed.connect = 2; - } else if ( entry === true && parsed.handles === 2 ) { - parsed.connect = 3; - } else if ( entry === false ) { - parsed.connect = 0; - } else { - throw new Error("noUiSlider: 'connect' option doesn't match handle count."); - } - } - - function testOrientation ( parsed, entry ) { - - // Set orientation to an a numerical value for easy - // array selection. - switch ( entry ){ - case 'horizontal': - parsed.ort = 0; - break; - case 'vertical': - parsed.ort = 1; - break; - default: - throw new Error("noUiSlider: 'orientation' option is invalid."); - } - } - - function testMargin ( parsed, entry ) { - - if ( !isNumeric(entry) ){ - throw new Error("noUiSlider: 'margin' option must be numeric."); - } - - parsed.margin = parsed.spectrum.getMargin(entry); - - if ( !parsed.margin ) { - throw new Error("noUiSlider: 'margin' option is only supported on linear sliders."); - } - } - - function testLimit ( parsed, entry ) { - - if ( !isNumeric(entry) ){ - throw new Error("noUiSlider: 'limit' option must be numeric."); - } - - parsed.limit = parsed.spectrum.getMargin(entry); - - if ( !parsed.limit ) { - throw new Error("noUiSlider: 'limit' option is only supported on linear sliders."); - } - } - - function testDirection ( parsed, entry ) { - - // Set direction as a numerical value for easy parsing. - // Invert connection for RTL sliders, so that the proper - // handles get the connect/background classes. - switch ( entry ) { - case 'ltr': - parsed.dir = 0; - break; - case 'rtl': - parsed.dir = 1; - parsed.connect = [0,2,1,3][parsed.connect]; - break; - default: - throw new Error("noUiSlider: 'direction' option was not recognized."); - } - } - - function testBehaviour ( parsed, entry ) { - - // Make sure the input is a string. - if ( typeof entry !== 'string' ) { - throw new Error("noUiSlider: 'behaviour' must be a string containing options."); - } - - // Check if the string contains any keywords. - // None are required. - var tap = entry.indexOf('tap') >= 0, - drag = entry.indexOf('drag') >= 0, - fixed = entry.indexOf('fixed') >= 0, - snap = entry.indexOf('snap') >= 0; - - parsed.events = { - tap: tap || snap, - drag: drag, - fixed: fixed, - snap: snap - }; - } - - function testFormat ( parsed, entry ) { - - parsed.format = entry; - - // Any object with a to and from method is supported. - if ( typeof entry.to === 'function' && typeof entry.from === 'function' ) { - return true; - } - - throw new Error( "noUiSlider: 'format' requires 'to' and 'from' methods."); - } - - // Test all developer settings and parse to assumption-safe values. - function testOptions ( options ) { - - var parsed = { - margin: 0, - limit: 0, - animate: true, - format: defaultFormatter - }, tests; - - // Tests are executed in the order they are presented here. - tests = { - 'step': { r: false, t: testStep }, - 'start': { r: true, t: testStart }, - 'connect': { r: true, t: testConnect }, - 'direction': { r: true, t: testDirection }, - 'snap': { r: false, t: testSnap }, - 'animate': { r: false, t: testAnimate }, - 'range': { r: true, t: testRange }, - 'orientation': { r: false, t: testOrientation }, - 'margin': { r: false, t: testMargin }, - 'limit': { r: false, t: testLimit }, - 'behaviour': { r: true, t: testBehaviour }, - 'format': { r: false, t: testFormat } - }; - - var defaults = { - 'connect': false, - 'direction': 'ltr', - 'behaviour': 'tap', - 'orientation': 'horizontal' - }; - - // Set defaults where applicable. - Object.keys(defaults).forEach(function ( name ) { - if ( options[name] === undefined ) { - options[name] = defaults[name]; - } - }); - - // Run all options through a testing mechanism to ensure correct - // input. It should be noted that options might get modified to - // be handled properly. E.g. wrapping integers in arrays. - Object.keys(tests).forEach(function( name ){ - - var test = tests[name]; - - // If the option isn't set, but it is required, throw an error. - if ( options[name] === undefined ) { - - if ( test.r ) { - throw new Error("noUiSlider: '" + name + "' is required."); - } - - return true; - } - - test.t( parsed, options[name] ); - }); - - // Forward pips options - parsed.pips = options.pips; - - // Pre-define the styles. - parsed.style = parsed.ort ? 'top' : 'left'; - - return parsed; - } - - - // Delimit proposed values for handle positions. - function getPositions ( a, b, delimit ) { - - // Add movement to current position. - var c = a + b[0], d = a + b[1]; - - // Only alter the other position on drag, - // not on standard sliding. - if ( delimit ) { - if ( c < 0 ) { - d += Math.abs(c); - } - if ( d > 100 ) { - c -= ( d - 100 ); - } - - // Limit values to 0 and 100. - return [limit(c), limit(d)]; - } - - return [c,d]; - } - - // Provide a clean event with standardized offset values. - function fixEvent ( e ) { - - // Prevent scrolling and panning on touch events, while - // attempting to slide. The tap event also depends on this. - e.preventDefault(); - - // Filter the event to register the type, which can be - // touch, mouse or pointer. Offset changes need to be - // made on an event specific basis. - var touch = e.type.indexOf('touch') === 0, - mouse = e.type.indexOf('mouse') === 0, - pointer = e.type.indexOf('pointer') === 0, - x,y, event = e; - - // IE10 implemented pointer events with a prefix; - if ( e.type.indexOf('MSPointer') === 0 ) { - pointer = true; - } - - if ( touch ) { - // noUiSlider supports one movement at a time, - // so we can select the first 'changedTouch'. - x = e.changedTouches[0].pageX; - y = e.changedTouches[0].pageY; - } - - if ( mouse || pointer ) { - x = e.clientX + window.pageXOffset; - y = e.clientY + window.pageYOffset; - } - - event.points = [x, y]; - event.cursor = mouse || pointer; // Fix #435 - - return event; - } - - // Append a handle to the base. - function addHandle ( direction, index ) { - - var origin = document.createElement('div'), - handle = document.createElement('div'), - additions = [ '-lower', '-upper' ]; - - if ( direction ) { - additions.reverse(); - } - - addClass(handle, Classes[3]); - addClass(handle, Classes[3] + additions[index]); - - addClass(origin, Classes[2]); - origin.appendChild(handle); - - return origin; - } - - // Add the proper connection classes. - function addConnection ( connect, target, handles ) { - - // Apply the required connection classes to the elements - // that need them. Some classes are made up for several - // segments listed in the class list, to allow easy - // renaming and provide a minor compression benefit. - switch ( connect ) { - case 1: addClass(target, Classes[7]); - addClass(handles[0], Classes[6]); - break; - case 3: addClass(handles[1], Classes[6]); - /* falls through */ - case 2: addClass(handles[0], Classes[7]); - /* falls through */ - case 0: addClass(target, Classes[6]); - break; - } - } - - // Add handles to the slider base. - function addHandles ( nrHandles, direction, base ) { - - var index, handles = []; - - // Append handles. - for ( index = 0; index < nrHandles; index += 1 ) { - - // Keep a list of all added handles. - handles.push( base.appendChild(addHandle( direction, index )) ); - } - - return handles; - } - - // Initialize a single slider. - function addSlider ( direction, orientation, target ) { - - // Apply classes and data to the target. - addClass(target, Classes[0]); - addClass(target, Classes[8 + direction]); - addClass(target, Classes[4 + orientation]); - - var div = document.createElement('div'); - addClass(div, Classes[1]); - target.appendChild(div); - return div; - } - - -function closure ( target, options ){ - - // All variables local to 'closure' are prefixed with 'scope_' - var scope_Target = target, - scope_Locations = [-1, -1], - scope_Base, - scope_Handles, - scope_Spectrum = options.spectrum, - scope_Values = [], - scope_Events = {}; - - - function getGroup ( mode, values, stepped ) { - - // Use the range. - if ( mode === 'range' || mode === 'steps' ) { - return scope_Spectrum.xVal; - } - - if ( mode === 'count' ) { - - // Divide 0 - 100 in 'count' parts. - var spread = ( 100 / (values-1) ), v, i = 0; - values = []; - - // List these parts and have them handled as 'positions'. - while ((v=i++*spread) <= 100 ) { - values.push(v); - } - - mode = 'positions'; - } - - if ( mode === 'positions' ) { - - // Map all percentages to on-range values. - return values.map(function( value ){ - return scope_Spectrum.fromStepping( stepped ? scope_Spectrum.getStep( value ) : value ); - }); - } - - if ( mode === 'values' ) { - - // If the value must be stepped, it needs to be converted to a percentage first. - if ( stepped ) { - - return values.map(function( value ){ - - // Convert to percentage, apply step, return to value. - return scope_Spectrum.fromStepping( scope_Spectrum.getStep( scope_Spectrum.toStepping( value ) ) ); - }); - - } - - // Otherwise, we can simply use the values. - return values; - } - } - - function generateSpread ( density, mode, group ) { - - var originalSpectrumDirection = scope_Spectrum.direction, - indexes = {}, - firstInRange = scope_Spectrum.xVal[0], - lastInRange = scope_Spectrum.xVal[scope_Spectrum.xVal.length-1], - ignoreFirst = false, - ignoreLast = false, - prevPct = 0; - - // This function loops the spectrum in an ltr linear fashion, - // while the toStepping method is direction aware. Trick it into - // believing it is ltr. - scope_Spectrum.direction = 0; - - // Create a copy of the group, sort it and filter away all duplicates. - group = unique(group.slice().sort(function(a, b){ return a - b; })); - - // Make sure the range starts with the first element. - if ( group[0] !== firstInRange ) { - group.unshift(firstInRange); - ignoreFirst = true; - } - - // Likewise for the last one. - if ( group[group.length - 1] !== lastInRange ) { - group.push(lastInRange); - ignoreLast = true; - } - - group.forEach(function ( current, index ) { - - // Get the current step and the lower + upper positions. - var step, i, q, - low = current, - high = group[index+1], - newPct, pctDifference, pctPos, type, - steps, realSteps, stepsize; - - // When using 'steps' mode, use the provided steps. - // Otherwise, we'll step on to the next subrange. - if ( mode === 'steps' ) { - step = scope_Spectrum.xNumSteps[ index ]; - } - - // Default to a 'full' step. - if ( !step ) { - step = high-low; - } - - // Low can be 0, so test for false. If high is undefined, - // we are at the last subrange. Index 0 is already handled. - if ( low === false || high === undefined ) { - return; - } - - // Find all steps in the subrange. - for ( i = low; i <= high; i += step ) { - - // Get the percentage value for the current step, - // calculate the size for the subrange. - newPct = scope_Spectrum.toStepping( i ); - pctDifference = newPct - prevPct; - - steps = pctDifference / density; - realSteps = Math.round(steps); - - // This ratio represents the ammount of percentage-space a point indicates. - // For a density 1 the points/percentage = 1. For density 2, that percentage needs to be re-devided. - // Round the percentage offset to an even number, then divide by two - // to spread the offset on both sides of the range. - stepsize = pctDifference/realSteps; - - // Divide all points evenly, adding the correct number to this subrange. - // Run up to <= so that 100% gets a point, event if ignoreLast is set. - for ( q = 1; q <= realSteps; q += 1 ) { - - // The ratio between the rounded value and the actual size might be ~1% off. - // Correct the percentage offset by the number of points - // per subrange. density = 1 will result in 100 points on the - // full range, 2 for 50, 4 for 25, etc. - pctPos = prevPct + ( q * stepsize ); - indexes[pctPos.toFixed(5)] = ['x', 0]; - } - - // Determine the point type. - type = (group.indexOf(i) > -1) ? 1 : ( mode === 'steps' ? 2 : 0 ); - - // Enforce the 'ignoreFirst' option by overwriting the type for 0. - if ( !index && ignoreFirst ) { - type = 0; - } - - if ( !(i === high && ignoreLast)) { - // Mark the 'type' of this point. 0 = plain, 1 = real value, 2 = step value. - indexes[newPct.toFixed(5)] = [i, type]; - } - - // Update the percentage count. - prevPct = newPct; - } - }); - - // Reset the spectrum. - scope_Spectrum.direction = originalSpectrumDirection; - - return indexes; - } - - function addMarking ( spread, filterFunc, formatter ) { - - var style = ['horizontal', 'vertical'][options.ort], - element = document.createElement('div'); - - addClass(element, 'noUi-pips'); - addClass(element, 'noUi-pips-' + style); - - function getSize( type ){ - return [ '-normal', '-large', '-sub' ][type]; - } - - function getTags( offset, source, values ) { - return 'class="' + source + ' ' + - source + '-' + style + ' ' + - source + getSize(values[1]) + - '" style="' + options.style + ': ' + offset + '%"'; - } - - function addSpread ( offset, values ){ - - if ( scope_Spectrum.direction ) { - offset = 100 - offset; - } - - // Apply the filter function, if it is set. - values[1] = (values[1] && filterFunc) ? filterFunc(values[0], values[1]) : values[1]; - - // Add a marker for every point - element.innerHTML += '
'; - - // Values are only appended for points marked '1' or '2'. - if ( values[1] ) { - element.innerHTML += '
' + formatter.to(values[0]) + '
'; - } - } - - // Append all points. - Object.keys(spread).forEach(function(a){ - addSpread(a, spread[a]); - }); - - return element; - } - - function pips ( grid ) { - - var mode = grid.mode, - density = grid.density || 1, - filter = grid.filter || false, - values = grid.values || false, - stepped = grid.stepped || false, - group = getGroup( mode, values, stepped ), - spread = generateSpread( density, mode, group ), - format = grid.format || { - to: Math.round - }; - - return scope_Target.appendChild(addMarking( - spread, - filter, - format - )); - } - - - // Shorthand for base dimensions. - function baseSize ( ) { - return scope_Base['offset' + ['Width', 'Height'][options.ort]]; - } - - // External event handling - function fireEvent ( event, handleNumber ) { - - if ( handleNumber !== undefined ) { - handleNumber = Math.abs(handleNumber - options.dir); - } - - Object.keys(scope_Events).forEach(function( targetEvent ) { - - var eventType = targetEvent.split('.')[0]; - - if ( event === eventType ) { - scope_Events[targetEvent].forEach(function( callback ) { - // .reverse is in place - // Return values as array, so arg_1[arg_2] is always valid. - callback( asArray(valueGet()), handleNumber, inSliderOrder(Array.prototype.slice.call(scope_Values)) ); - }); - } - }); - } - - // Returns the input array, respecting the slider direction configuration. - function inSliderOrder ( values ) { - - // If only one handle is used, return a single value. - if ( values.length === 1 ){ - return values[0]; - } - - if ( options.dir ) { - return values.reverse(); - } - - return values; - } - - - // Handler for attaching events trough a proxy. - function attach ( events, element, callback, data ) { - - // This function can be used to 'filter' events to the slider. - // element is a node, not a nodeList - - var method = function ( e ){ - - if ( scope_Target.hasAttribute('disabled') ) { - return false; - } - - // Stop if an active 'tap' transition is taking place. - if ( hasClass(scope_Target, Classes[14]) ) { - return false; - } - - e = fixEvent(e); - - // Ignore right or middle clicks on start #454 - if ( events === actions.start && e.buttons !== undefined && e.buttons > 1 ) { - return false; - } - - e.calcPoint = e.points[ options.ort ]; - - // Call the event handler with the event [ and additional data ]. - callback ( e, data ); - - }, methods = []; - - // Bind a closure on the target for every event type. - events.split(' ').forEach(function( eventName ){ - element.addEventListener(eventName, method, false); - methods.push([eventName, method]); - }); - - return methods; - } - - // Handle movement on document for handle and range drag. - function move ( event, data ) { - - var handles = data.handles || scope_Handles, positions, state = false, - proposal = ((event.calcPoint - data.start) * 100) / baseSize(), - handleNumber = handles[0] === scope_Handles[0] ? 0 : 1, i; - - // Calculate relative positions for the handles. - positions = getPositions( proposal, data.positions, handles.length > 1); - - state = setHandle ( handles[0], positions[handleNumber], handles.length === 1 ); - - if ( handles.length > 1 ) { - - state = setHandle ( handles[1], positions[handleNumber?0:1], false ) || state; - - if ( state ) { - // fire for both handles - for ( i = 0; i < data.handles.length; i++ ) { - fireEvent('slide', i); - } - } - } else if ( state ) { - // Fire for a single handle - fireEvent('slide', handleNumber); - } - } - - // Unbind move events on document, call callbacks. - function end ( event, data ) { - - // The handle is no longer active, so remove the class. - var active = scope_Base.getElementsByClassName(Classes[15]), - handleNumber = data.handles[0] === scope_Handles[0] ? 0 : 1; - - if ( active.length ) { - removeClass(active[0], Classes[15]); - } - - // Remove cursor styles and text-selection events bound to the body. - if ( event.cursor ) { - document.body.style.cursor = ''; - document.body.removeEventListener('selectstart', document.body.noUiListener); - } - - var d = document.documentElement; - - // Unbind the move and end events, which are added on 'start'. - d.noUiListeners.forEach(function( c ) { - d.removeEventListener(c[0], c[1]); - }); - - // Remove dragging class. - removeClass(scope_Target, Classes[12]); - - // Fire the change and set events. - fireEvent('set', handleNumber); - fireEvent('change', handleNumber); - } - - // Bind move events on document. - function start ( event, data ) { - - var d = document.documentElement; - - // Mark the handle as 'active' so it can be styled. - if ( data.handles.length === 1 ) { - addClass(data.handles[0].children[0], Classes[15]); - - // Support 'disabled' handles - if ( data.handles[0].hasAttribute('disabled') ) { - return false; - } - } - - // A drag should never propagate up to the 'tap' event. - event.stopPropagation(); - - // Attach the move and end events. - var moveEvent = attach(actions.move, d, move, { - start: event.calcPoint, - handles: data.handles, - positions: [ - scope_Locations[0], - scope_Locations[scope_Handles.length - 1] - ] - }), endEvent = attach(actions.end, d, end, { - handles: data.handles - }); - - d.noUiListeners = moveEvent.concat(endEvent); - - // Text selection isn't an issue on touch devices, - // so adding cursor styles can be skipped. - if ( event.cursor ) { - - // Prevent the 'I' cursor and extend the range-drag cursor. - document.body.style.cursor = getComputedStyle(event.target).cursor; - - // Mark the target with a dragging state. - if ( scope_Handles.length > 1 ) { - addClass(scope_Target, Classes[12]); - } - - var f = function(){ - return false; - }; - - document.body.noUiListener = f; - - // Prevent text selection when dragging the handles. - document.body.addEventListener('selectstart', f, false); - } - } - - // Move closest handle to tapped location. - function tap ( event ) { - - var location = event.calcPoint, total = 0, handleNumber, to; - - // The tap event shouldn't propagate up and cause 'edge' to run. - event.stopPropagation(); - - // Add up the handle offsets. - scope_Handles.forEach(function(a){ - total += offset(a)[ options.style ]; - }); - - // Find the handle closest to the tapped position. - handleNumber = ( location < total/2 || scope_Handles.length === 1 ) ? 0 : 1; - - location -= offset(scope_Base)[ options.style ]; - - // Calculate the new position. - to = ( location * 100 ) / baseSize(); - - if ( !options.events.snap ) { - // Flag the slider as it is now in a transitional state. - // Transition takes 300 ms, so re-enable the slider afterwards. - addClassFor( scope_Target, Classes[14], 300 ); - } - - // Support 'disabled' handles - if ( scope_Handles[handleNumber].hasAttribute('disabled') ) { - return false; - } - - // Find the closest handle and calculate the tapped point. - // The set handle to the new position. - setHandle( scope_Handles[handleNumber], to ); - - fireEvent('slide', handleNumber); - fireEvent('set', handleNumber); - fireEvent('change', handleNumber); - - if ( options.events.snap ) { - start(event, { handles: [scope_Handles[total]] }); - } - } - - // Attach events to several slider parts. - function events ( behaviour ) { - - var i, drag; - - // Attach the standard drag event to the handles. - if ( !behaviour.fixed ) { - - for ( i = 0; i < scope_Handles.length; i += 1 ) { - - // These events are only bound to the visual handle - // element, not the 'real' origin element. - attach ( actions.start, scope_Handles[i].children[0], start, { - handles: [ scope_Handles[i] ] - }); - } - } - - // Attach the tap event to the slider base. - if ( behaviour.tap ) { - - attach ( actions.start, scope_Base, tap, { - handles: scope_Handles - }); - } - - // Make the range dragable. - if ( behaviour.drag ){ - - drag = [scope_Base.getElementsByClassName( Classes[7] )[0]]; - addClass(drag[0], Classes[10]); - - // When the range is fixed, the entire range can - // be dragged by the handles. The handle in the first - // origin will propagate the start event upward, - // but it needs to be bound manually on the other. - if ( behaviour.fixed ) { - drag.push(scope_Handles[(drag[0] === scope_Handles[0] ? 1 : 0)].children[0]); - } - - drag.forEach(function( element ) { - attach ( actions.start, element, start, { - handles: scope_Handles - }); - }); - } - } - - - // Test suggested values and apply margin, step. - function setHandle ( handle, to, noLimitOption ) { - - var trigger = handle !== scope_Handles[0] ? 1 : 0, - lowerMargin = scope_Locations[0] + options.margin, - upperMargin = scope_Locations[1] - options.margin, - lowerLimit = scope_Locations[0] + options.limit, - upperLimit = scope_Locations[1] - options.limit; - - // For sliders with multiple handles, - // limit movement to the other handle. - // Apply the margin option by adding it to the handle positions. - if ( scope_Handles.length > 1 ) { - to = trigger ? Math.max( to, lowerMargin ) : Math.min( to, upperMargin ); - } - - // The limit option has the opposite effect, limiting handles to a - // maximum distance from another. Limit must be > 0, as otherwise - // handles would be unmoveable. 'noLimitOption' is set to 'false' - // for the .val() method, except for pass 4/4. - if ( noLimitOption !== false && options.limit && scope_Handles.length > 1 ) { - to = trigger ? Math.min ( to, lowerLimit ) : Math.max( to, upperLimit ); - } - - // Handle the step option. - to = scope_Spectrum.getStep( to ); - - // Limit to 0/100 for .val input, trim anything beyond 7 digits, as - // JavaScript has some issues in its floating point implementation. - to = limit(parseFloat(to.toFixed(7))); - - // Return false if handle can't move. - if ( to === scope_Locations[trigger] ) { - return false; - } - - // Set the handle to the new position. - handle.style[options.style] = to + '%'; - - // Force proper handle stacking - if ( !handle.previousSibling ) { - removeClass(handle, Classes[17]); - if ( to > 50 ) { - addClass(handle, Classes[17]); - } - } - - // Update locations. - scope_Locations[trigger] = to; - - // Convert the value to the slider stepping/range. - scope_Values[trigger] = scope_Spectrum.fromStepping( to ); - - fireEvent('update', trigger); - - return true; - } - - // Loop values from value method and apply them. - function setValues ( count, values ) { - - var i, trigger, to; - - // With the limit option, we'll need another limiting pass. - if ( options.limit ) { - count += 1; - } - - // If there are multiple handles to be set run the setting - // mechanism twice for the first handle, to make sure it - // can be bounced of the second one properly. - for ( i = 0; i < count; i += 1 ) { - - trigger = i%2; - - // Get the current argument from the array. - to = values[trigger]; - - // Setting with null indicates an 'ignore'. - // Inputting 'false' is invalid. - if ( to !== null && to !== false ) { - - // If a formatted number was passed, attemt to decode it. - if ( typeof to === 'number' ) { - to = String(to); - } - - to = options.format.from( to ); - - // Request an update for all links if the value was invalid. - // Do so too if setting the handle fails. - if ( to === false || isNaN(to) || setHandle( scope_Handles[trigger], scope_Spectrum.toStepping( to ), i === (3 - options.dir) ) === false ) { - fireEvent('update', trigger); - } - } - } - } - - // Set the slider value. - function valueSet ( input ) { - - var count, values = asArray( input ), i; - - // The RTL settings is implemented by reversing the front-end, - // internal mechanisms are the same. - if ( options.dir && options.handles > 1 ) { - values.reverse(); - } - - // Animation is optional. - // Make sure the initial values where set before using animated placement. - if ( options.animate && scope_Locations[0] !== -1 ) { - addClassFor( scope_Target, Classes[14], 300 ); - } - - // Determine how often to set the handles. - count = scope_Handles.length > 1 ? 3 : 1; - - if ( values.length === 1 ) { - count = 1; - } - - setValues ( count, values ); - - // Fire the 'set' event for both handles. - for ( i = 0; i < scope_Handles.length; i++ ) { - fireEvent('set', i); - } - } - - // Get the slider value. - function valueGet ( ) { - - var i, retour = []; - - // Get the value from all handles. - for ( i = 0; i < options.handles; i += 1 ){ - retour[i] = options.format.to( scope_Values[i] ); - } - - return inSliderOrder( retour ); - } - - // Removes classes from the root and empties it. - function destroy ( ) { - Classes.forEach(function(cls){ - if ( !cls ) { return; } // Ignore empty classes - removeClass(scope_Target, cls); - }); - scope_Target.innerHTML = ''; - delete scope_Target.noUiSlider; - } - - // Get the current step size for the slider. - function getCurrentStep ( ) { - - // Check all locations, map them to their stepping point. - // Get the step point, then find it in the input list. - var retour = scope_Locations.map(function( location, index ){ - - var step = scope_Spectrum.getApplicableStep( location ), - - // As per #391, the comparison for the decrement step can have some rounding issues. - // Round the value to the precision used in the step. - stepDecimals = countDecimals(String(step[2])), - - // Get the current numeric value - value = scope_Values[index], - - // To move the slider 'one step up', the current step value needs to be added. - // Use null if we are at the maximum slider value. - increment = location === 100 ? null : step[2], - - // Going 'one step down' might put the slider in a different sub-range, so we - // need to switch between the current or the previous step. - prev = Number((value - step[2]).toFixed(stepDecimals)), - - // If the value fits the step, return the current step value. Otherwise, use the - // previous step. Return null if the slider is at its minimum value. - decrement = location === 0 ? null : (prev >= step[1]) ? step[2] : (step[0] || false); - - return [decrement, increment]; - }); - - // Return values in the proper order. - return inSliderOrder( retour ); - } - - // Attach an event to this slider, possibly including a namespace - function bindEvent ( namespacedEvent, callback ) { - scope_Events[namespacedEvent] = scope_Events[namespacedEvent] || []; - scope_Events[namespacedEvent].push(callback); - - // If the event bound is 'update,' fire it immediately for all handles. - if ( namespacedEvent.split('.')[0] === 'update' ) { - scope_Handles.forEach(function(a, index){ - fireEvent('update', index); - }); - } - } - - // Undo attachment of event - function removeEvent ( namespacedEvent ) { - - var event = namespacedEvent.split('.')[0], - namespace = namespacedEvent.substring(event.length); - - Object.keys(scope_Events).forEach(function( bind ){ - - var tEvent = bind.split('.')[0], - tNamespace = bind.substring(tEvent.length); - - if ( (!event || event === tEvent) && (!namespace || namespace === tNamespace) ) { - delete scope_Events[bind]; - } - }); - } - - - // Throw an error if the slider was already initialized. - if ( scope_Target.noUiSlider ) { - throw new Error('Slider was already initialized.'); - } - - - // Create the base element, initialise HTML and set classes. - // Add handles and links. - scope_Base = addSlider( options.dir, options.ort, scope_Target ); - scope_Handles = addHandles( options.handles, options.dir, scope_Base ); - - // Set the connect classes. - addConnection ( options.connect, scope_Target, scope_Handles ); - - // Attach user events. - events( options.events ); - - if ( options.pips ) { - pips(options.pips); - } - - return { - destroy: destroy, - steps: getCurrentStep, - on: bindEvent, - off: removeEvent, - get: valueGet, - set: valueSet - }; - -} - - - // Run the standard initializer - function initialize ( target, originalOptions ) { - - if ( !target.nodeName ) { - throw new Error('noUiSlider.create requires a single element.'); - } - - // Test the options and create the slider environment; - var options = testOptions( originalOptions, target ), - slider = closure( target, options ); - - // Use the public value method to set the start values. - slider.set(options.start); - - target.noUiSlider = slider; - } - - // Use an object instead of a function for future expansibility; - return { - create: initialize - }; - -})); \ No newline at end of file diff --git a/content/lib/pencil-tracer.js b/content/lib/pencil-tracer.js index 301d98ac..6c25d5c8 100644 --- a/content/lib/pencil-tracer.js +++ b/content/lib/pencil-tracer.js @@ -1,20 +1,23 @@ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pencilTracer = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o").expressions[0].constructor, 'Param': this.coffee.nodes("(a)->").expressions[0].params[0].constructor, - 'Splat': this.coffee.nodes("[a...]").expressions[0].base.objects[0].constructor, - 'Expansion': this.coffee.nodes("[...]").expressions[0].base.objects[0].constructor, 'While': this.coffee.nodes("0 while true").expressions[0].constructor, 'Op': this.coffee.nodes("1+1").expressions[0].constructor, - 'In': this.coffee.nodes("0 in []").expressions[0].constructor, 'Try': this.coffee.nodes("try").expressions[0].constructor, 'Throw': this.coffee.nodes("throw 0").expressions[0].constructor, - 'Existence': this.coffee.nodes("a?").expressions[0].constructor, 'Parens': this.coffee.nodes("(0)").expressions[0].base.constructor, 'For': this.coffee.nodes("0 for a in []").expressions[0].constructor, 'Switch': this.coffee.nodes("switch a\n when 0 then 0").expressions[0].constructor, @@ -68,41 +58,296 @@ } }; - CoffeeScriptInstrumenter.prototype.createInstrumentedNode = function(targetNode, eventType) { - var eventObj, instrumentedNode, locationData, locationObj, varsObj; - if (targetNode instanceof this.nodeTypes.IcedTailCall) { - targetNode = targetNode.value; + CoffeeScriptInstrumenter.prototype.temporaryVariable = function(base) { + var curName, index, name; + name = "_penciltracer_" + base; + index = 0; + while (true) { + curName = name + index; + if (indexOf.call(this.referencedVars, curName) < 0) { + this.referencedVars.push(curName); + return curName; + } + index++; + } + }; + + CoffeeScriptInstrumenter.prototype.lastNonComment = function(list) { + var i; + i = list.length; + while (i--) { + if (!(list[i] instanceof this.nodeTypes.Comment)) { + return list[i]; + } + } + return null; + }; + + CoffeeScriptInstrumenter.prototype.createInstrumentedNode = function(eventType, options) { + var eventObj, extra, f, functionCalls, instrumentedNode, location, locationObj, name, ref, ref1, ref2, soakify, vars; + if (options == null) { + options = {}; + } + if (options.node instanceof this.nodeTypes.IcedTailCall) { + options.node = options.node.value; + } + location = (ref = options.location) != null ? ref : options.node.locationData; + if (eventType !== "leave") { + vars = (ref1 = options.vars) != null ? ref1 : (eventType === "enter" ? this.findArguments(options.node) : this.findVariables(options.node)); + } + if (eventType === "after") { + functionCalls = (ref2 = options.functionCalls) != null ? ref2 : this.findFunctionCalls(options.node); + } + locationObj = "{ first_line: " + (location.first_line + 1) + ","; + locationObj += " first_column: " + (location.first_column + 1) + ","; + locationObj += " last_line: " + (location.last_line + 1) + ","; + locationObj += " last_column: " + (location.last_column + 1) + " }"; + soakify = function(name) { + if (name.indexOf(".") === -1) { + return "(if typeof " + name + " is 'undefined' then undefined else " + name + ")"; + } else { + return name.replace(/\./g, "?."); + } + }; + extra = (function() { + switch (eventType) { + case "before": + case "after": + return "vars: [" + ((function() { + var j, len, results; + results = []; + for (j = 0, len = vars.length; j < len; j++) { + name = vars[j]; + results.push("{name: '" + name + "', value: " + (soakify(name)) + "}"); + } + return results; + })()) + "]"; + case "enter": + return "vars: [" + ((function() { + var j, len, results; + results = []; + for (j = 0, len = vars.length; j < len; j++) { + name = vars[j]; + results.push("{name: '" + name + "', value: " + name + "}"); + } + return results; + })()) + "]"; + case "leave": + return "returnOrThrow: " + options.returnOrThrowVar; + } + })(); + if (eventType === "after") { + extra += ", functionCalls: [" + ((function() { + var j, len, results; + results = []; + for (j = 0, len = functionCalls.length; j < len; j++) { + f = functionCalls[j]; + results.push("{name: '" + f.name + "', value: " + f.tempVar + "}"); + } + return results; + })()) + "]"; } - locationData = targetNode.locationData; - locationObj = "{ first_line: " + (locationData.first_line + 1) + ","; - locationObj += " first_column: " + (locationData.first_column + 1) + ","; - locationObj += " last_line: " + (locationData.last_line + 1) + ","; - locationObj += " last_column: " + (locationData.last_column + 1) + " }"; - eventObj = this.options.trackVariables ? (varsObj = targetNode.pencilTracerScope.toCode(this.findVariables(targetNode)), "{ location: " + locationObj + ", type: '" + eventType + "', vars: " + varsObj + " }") : "{ location: " + locationObj + ", type: '" + eventType + "' }"; + eventObj = "{ location: " + locationObj + ", type: '" + eventType + "', " + extra + " }"; instrumentedNode = this.coffee.nodes(this.options.traceFunc + "(" + eventObj + ")").expressions[0]; instrumentedNode.pencilTracerInstrumented = true; return instrumentedNode; }; - CoffeeScriptInstrumenter.prototype.createInstrumentedExpr = function(targetNode, eventType, originalExpr) { - var parensBlock; + CoffeeScriptInstrumenter.prototype.createInstrumentedExpr = function(originalExpr) { + var parensBlock, tempVar; + tempVar = this.temporaryVariable("temp"); parensBlock = this.coffee.nodes("(0)").expressions[0]; parensBlock.base.body.expressions = []; - parensBlock.base.body.expressions[0] = this.createInstrumentedNode(targetNode, "code"); - parensBlock.base.body.expressions[1] = originalExpr; + parensBlock.base.body.expressions[0] = this.createInstrumentedNode("before", { + node: originalExpr + }); + parensBlock.base.body.expressions[1] = this.createAssignNode(tempVar, originalExpr); + parensBlock.base.body.expressions[2] = this.createInstrumentedNode("after", { + node: originalExpr + }); + parensBlock.base.body.expressions[3] = this.coffee.nodes(tempVar).expressions[0]; return parensBlock; }; + CoffeeScriptInstrumenter.prototype.createAssignNode = function(varName, valueNode) { + var assignNode; + assignNode = this.coffee.nodes(varName + " = 0").expressions[0]; + assignNode.value = valueNode; + return assignNode; + }; + + CoffeeScriptInstrumenter.prototype.findVariables = function(node, parent, vars) { + var j, lastProp, len, name, prop, ref, skip; + if (parent == null) { + parent = null; + } + if (vars == null) { + vars = []; + } + if (node instanceof this.nodeTypes.Value && node.base instanceof this.nodeTypes.Literal && node.base.isAssignable()) { + skip = parent instanceof this.nodeTypes.Assign && parent.context === "object" && parent.variable === node; + skip || (skip = parent instanceof this.nodeTypes.Call && parent.variable === node && node.properties.length === 0); + if (!skip) { + name = node["this"] ? "@" : node.base.value + "."; + lastProp = node.properties[node.properties.length - 1]; + ref = node.properties; + for (j = 0, len = ref.length; j < len; j++) { + prop = ref[j]; + if (!(prop instanceof this.nodeTypes.Access) || prop.soak || (prop === lastProp && parent instanceof this.nodeTypes.Call && parent.variable === node)) { + break; + } + name += prop.name.value + "."; + } + if (name !== "@") { + name = name.slice(0, -1); + } + if (vars.indexOf(name) === -1) { + vars.push(name); + } + } + } + node.eachChild((function(_this) { + return function(child) { + skip = child instanceof _this.nodeTypes.Block && !(node instanceof _this.nodeTypes.Parens); + skip || (skip = child instanceof _this.nodeTypes.Code); + skip || (skip = !_this.shouldInstrumentNode(child)); + skip || (skip = node instanceof _this.nodeTypes.Defer); + if (!skip) { + return _this.findVariables(child, node, vars); + } + }; + })(this)); + return vars; + }; + + CoffeeScriptInstrumenter.prototype.findArguments = function(codeNode) { + var args, j, len, name, paramNode, ref; + if (!(codeNode instanceof this.nodeTypes.Code)) { + throw new Error("findArguments() expects a Code node"); + } + args = []; + ref = codeNode.params; + for (j = 0, len = ref.length; j < len; j++) { + paramNode = ref[j]; + if (paramNode instanceof this.nodeTypes.Param) { + name = paramNode.name; + if (name instanceof this.nodeTypes.Literal) { + args.push(name.value); + } else if (name instanceof this.nodeTypes.Value) { + args.push("@" + name.properties[0].name.value); + } else { + args.push.apply(args, this.findVariables(name)); + } + } + } + return args; + }; + + CoffeeScriptInstrumenter.prototype.findFunctionCalls = function(node, parent, grandparent, vars) { + var j, lastProp, len, name, prop, ref, soak; + if (parent == null) { + parent = null; + } + if (grandparent == null) { + grandparent = null; + } + if (vars == null) { + vars = []; + } + if (node instanceof this.nodeTypes.Call && !(grandparent instanceof this.nodeTypes.Op && grandparent.operator === "new")) { + soak = node.soak; + if (node.variable instanceof this.nodeTypes.Value) { + ref = node.variable.properties; + for (j = 0, len = ref.length; j < len; j++) { + prop = ref[j]; + soak || (soak = prop.soak); + } + } + if (!soak) { + name = ""; + if (node.isSuper) { + name = "super"; + } else if (node.variable instanceof this.nodeTypes.Value) { + if (node.variable.properties.length > 0) { + lastProp = node.variable.properties[node.variable.properties.length - 1]; + if (lastProp instanceof this.nodeTypes.Access) { + name = lastProp.name.value; + } + } else if (node.variable.base instanceof this.nodeTypes.Literal) { + name = node.variable.base.value; + } + } + node.pencilTracerReturnVar = this.temporaryVariable("returnVar"); + vars.push({ + name: name, + tempVar: node.pencilTracerReturnVar + }); + } + } + node.eachChild((function(_this) { + return function(child) { + var skip; + skip = child instanceof _this.nodeTypes.Block && !(node instanceof _this.nodeTypes.Parens); + skip || (skip = child instanceof _this.nodeTypes.Code); + skip || (skip = !_this.shouldInstrumentNode(child)); + if (!skip) { + return _this.findFunctionCalls(child, node, parent, vars); + } + }; + })(this)); + return vars; + }; + + CoffeeScriptInstrumenter.prototype.nodeIsObj = function(node) { + return node instanceof this.nodeTypes.Value && node.isObject(true); + }; + + CoffeeScriptInstrumenter.prototype.nodeIsClassProperty = function(node, className) { + return this.nodeIsObj(node) || (node instanceof this.nodeTypes.Assign && node.variable.looksStatic(className)) || (node instanceof this.nodeTypes.Assign && node.variable["this"]); + }; + CoffeeScriptInstrumenter.prototype.shouldSkipNode = function(node) { return node.pencilTracerInstrumented || node instanceof this.nodeTypes.IcedRuntime; }; CoffeeScriptInstrumenter.prototype.shouldInstrumentNode = function(node) { - return !node.pencilTracerInstrumented && !(node instanceof this.nodeTypes.IcedRuntime) && (!(node instanceof this.nodeTypes.IcedTailCall) || node.value) && !(node instanceof this.nodeTypes.Comment) && !(node instanceof this.nodeTypes.While) && !(node instanceof this.nodeTypes.Switch) && !(node instanceof this.nodeTypes.If); + return !node.pencilTracerInstrumented && !(node instanceof this.nodeTypes.IcedRuntime) && (!(node instanceof this.nodeTypes.IcedTailCall) || node.value) && !(node instanceof this.nodeTypes.Comment) && !(node instanceof this.nodeTypes.For) && !(node instanceof this.nodeTypes.While) && !(node instanceof this.nodeTypes.Switch) && !(node instanceof this.nodeTypes.If) && !(node instanceof this.nodeTypes.Class) && !(node instanceof this.nodeTypes.Try) && !(node instanceof this.nodeTypes.Await); + }; + + CoffeeScriptInstrumenter.prototype.mapChildrenArray = function(children, func) { + var child, index, j, len, results; + results = []; + for (index = j = 0, len = children.length; j < len; index = ++j) { + child = children[index]; + if (isArray(child)) { + results.push(this.mapChildrenArray(child, func)); + } else { + results.push(children[index] = func(child)); + } + } + return results; + }; + + CoffeeScriptInstrumenter.prototype.mapChildren = function(node, func) { + var attr, childrenAttrs, j, len, results; + childrenAttrs = node.children.slice(); + childrenAttrs.push("icedContinuationBlock"); + results = []; + for (j = 0, len = childrenAttrs.length; j < len; j++) { + attr = childrenAttrs[j]; + if (node[attr]) { + if (isArray(node[attr])) { + results.push(this.mapChildrenArray(node[attr], func)); + } else { + results.push(node[attr] = func(node[attr])); + } + } + } + return results; }; CoffeeScriptInstrumenter.prototype.compileAst = function(ast, originalCode, compileOptions) { - var SourceMap, answer, compilerName, currentColumn, currentLine, fragment, fragments, header, i, js, len, map, newLines; + var SourceMap, answer, compilerName, currentColumn, currentLine, fragment, fragments, header, j, js, len, map, newLines; SourceMap = this.coffee.compile("", { sourceMap: true }).sourceMap.constructor; @@ -119,8 +364,8 @@ } currentColumn = 0; js = ""; - for (i = 0, len = fragments.length; i < len; i++) { - fragment = fragments[i]; + for (j = 0, len = fragments.length; j < len; j++) { + fragment = fragments[j]; if (compileOptions.sourceMap) { if (fragment.locationData && !/^[;\s]*$/.test(fragment.code)) { map.add([fragment.locationData.first_line, fragment.locationData.first_column], [currentLine, currentColumn], { @@ -154,161 +399,229 @@ } }; - CoffeeScriptInstrumenter.prototype.findVariables = function(node, parent, vars) { - var skip; - if (parent == null) { - parent = null; - } - if (vars == null) { - vars = []; - } - if (node instanceof this.nodeTypes.Value && node.base instanceof this.nodeTypes.Literal && node.base.isAssignable()) { - skip = parent instanceof this.nodeTypes.Assign && parent.context === "object" && parent.variable === node; - if (!skip) { - if (vars.indexOf(node.base.value) === -1) { - vars.push(node.base.value); - } - } - } - node.eachChild((function(_this) { - return function(child) { - return _this.findVariables(child, node, vars); - }; - })(this)); - return vars; - }; - - CoffeeScriptInstrumenter.prototype.findArguments = function(paramNode) { - var name; - if (!(paramNode instanceof this.nodeTypes.Param)) { - throw new Error("findArguments() expects a Param node"); - } - name = paramNode.name; - if (name instanceof this.nodeTypes.Literal) { - return [name.value]; - } else if (name instanceof this.nodeTypes.Value) { - return []; - } else { - return this.findVariables(name); - } - }; - - CoffeeScriptInstrumenter.prototype.findScopes = function(node, parent, scopes, depth) { - var arg, i, j, len, len1, param, ref, ref1; + CoffeeScriptInstrumenter.prototype.instrumentTree = function(node, parent, inClass, returnOrThrowVar) { + var after, afterNode, before, beforeNode, block, caseClause, childIndex, children, expression, getVars, i, j, k, lastChild, len, len1, location, objValue, parensBlock, prop, recursed, ref, ref1, ref2, returnValue, temp, thrownValue, tryNode, vars; if (parent == null) { parent = null; } - if (scopes == null) { - scopes = []; - } - if (depth == null) { - depth = 0; - } - if (node instanceof this.nodeTypes.Block) { - depth += 1; - scopes[depth] = new Scope(scopes[depth - 1]); - if (parent instanceof this.nodeTypes.Code) { - ref = parent.params; - for (i = 0, len = ref.length; i < len; i++) { - param = ref[i]; - ref1 = this.findArguments(param); - for (j = 0, len1 = ref1.length; j < len1; j++) { - arg = ref1[j]; - scopes[depth].add(arg, "argument"); - } - } - } - } - node.pencilTracerScope = scopes[depth]; - if (node instanceof this.nodeTypes.Assign && node.context !== "object") { - if (node.variable.base instanceof this.nodeTypes.Literal) { - scopes[depth].add(node.variable.base.value, "variable"); - } - } - node.eachChild((function(_this) { - return function(child) { - return _this.findScopes(child, node, scopes, depth); - }; - })(this)); - if (node.icedContinuationBlock != null) { - return this.findScopes(node.icedContinuationBlock, node, scopes, depth); - } - }; - - CoffeeScriptInstrumenter.prototype.instrumentTree = function(node, parent) { - var caseClause, childIndex, children, expression, i, instrumentedNode, len, ref, tryBlock, tryNode; - if (parent == null) { - parent = null; + if (inClass == null) { + inClass = false; } if (this.shouldSkipNode(node)) { return; } - if (node instanceof this.nodeTypes.Block && !(parent instanceof this.nodeTypes.Parens) && !(parent instanceof this.nodeTypes.Class)) { + if (node instanceof this.nodeTypes.Class) { + inClass = node; + } + if (this.nodeIsObj(node)) { + inClass = false; + } + recursed = false; + if (node instanceof this.nodeTypes.Block && !(parent instanceof this.nodeTypes.Parens)) { children = node.expressions; + lastChild = this.lastNonComment(children); childIndex = 0; + if (!returnOrThrowVar) { + returnOrThrowVar = this.temporaryVariable("returnOrThrow"); + children.unshift(this.coffee.nodes(returnOrThrowVar + " = {}").expressions[0]); + childIndex = 1; + } while (childIndex < children.length) { expression = children[childIndex]; + if (inClass && this.nodeIsObj(expression) && expression.base.properties.length > 1) { + children.splice(childIndex, 1); + ref = expression.base.properties; + for (i = j = 0, len = ref.length; j < len; i = ++j) { + prop = ref[i]; + objValue = this.coffee.nodes("{}").expressions[0]; + objValue.locationData = objValue.base.locationData = prop.locationData; + objValue.base.properties = objValue.base.objects = [prop]; + objValue.base.generated = expression.base.generated; + children.splice(childIndex + i, 0, objValue); + } + expression = children[childIndex]; + } if (this.shouldInstrumentNode(expression)) { - instrumentedNode = this.createInstrumentedNode(expression, "code"); - children.splice(childIndex, 0, instrumentedNode); + beforeNode = this.createInstrumentedNode("before", { + node: expression + }); + afterNode = this.createInstrumentedNode("after", { + node: expression + }); + children.splice(childIndex, 0, beforeNode); + childIndex++; + children.splice(childIndex + 1, 0, afterNode); childIndex++; + if (expression.pencilTracerReturnVar) { + children[childIndex - 1] = this.createAssignNode(expression.pencilTracerReturnVar, expression); + } + if (expression instanceof this.nodeTypes.Return) { + returnValue = expression.expression || this.coffee.nodes("undefined").expressions[0]; + if (returnValue.pencilTracerReturnVar) { + returnValue = this.createAssignNode(returnValue.pencilTracerReturnVar, returnValue); + } + children[childIndex - 1] = this.createAssignNode(returnOrThrowVar + ".value", returnValue); + children.splice(childIndex + 1, 0, this.coffee.nodes("return " + returnOrThrowVar + ".value").expressions[0]); + childIndex++; + } else if (expression instanceof this.nodeTypes.Throw) { + thrownValue = expression.expression; + if (thrownValue.pencilTracerReturnVar) { + thrownValue = this.createAssignNode(thrownValue.pencilTracerReturnVar, thrownValue); + } + children[childIndex - 1] = this.createAssignNode(returnOrThrowVar + ".value", thrownValue); + children.splice(childIndex + 1, 0, this.coffee.nodes("throw " + returnOrThrowVar + ".value").expressions[0]); + childIndex++; + } else if (expression instanceof this.nodeTypes.Literal && ((ref1 = expression.value) === "break" || ref1 === "continue")) { + temp = children[childIndex]; + children[childIndex] = children[childIndex - 1]; + children[childIndex - 1] = temp; + } else if (expression === lastChild && !expression.jumps() && !(expression instanceof this.nodeTypes.Await) && !(inClass && this.nodeIsClassProperty(expression, inClass.determineName())) && !(parent instanceof this.nodeTypes.Try && parent.ensure === node)) { + children[childIndex - 1] = this.createAssignNode(returnOrThrowVar + ".value", children[childIndex - 1]); + children.splice(childIndex + 1, 0, this.coffee.nodes(returnOrThrowVar + ".value").expressions[0]); + children[childIndex + 1].icedHasAutocbFlag = expression.icedHasAutocbFlag; + childIndex++; + } } - this.instrumentTree(expression, node); + this.instrumentTree(expression, node, inClass, returnOrThrowVar); childIndex++; } - if (parent instanceof this.nodeTypes.For) { - instrumentedNode = this.createInstrumentedNode(parent, "code"); - return children.unshift(instrumentedNode); + recursed = true; + } else if (node instanceof this.nodeTypes.For) { + if (!node.range) { + node.source = this.createInstrumentedExpr(node.source); } - } else if (node instanceof this.nodeTypes.While) { - node.condition = this.createInstrumentedExpr(node, "code", node.condition); - return node.eachChild((function(_this) { - return function(child) { - return _this.instrumentTree(child, node); + if (node.guard) { + node.guard = this.createInstrumentedExpr(node.guard); + } + if (node.step) { + node.step = this.createInstrumentedExpr(node.step); + } + getVars = (function(_this) { + return function(n) { + if (n instanceof _this.nodeTypes.Literal) { + return [n.value]; + } else { + return _this.findVariables(n); + } }; - })(this)); + })(this); + if (node.name && node.index) { + if (node.object) { + location = { + first_line: node.name.locationData.first_line, + first_column: node.name.locationData.first_column, + last_line: node.index.locationData.last_line, + last_column: node.index.locationData.last_column + }; + } else { + location = { + first_line: node.index.locationData.first_line, + first_column: node.index.locationData.first_column, + last_line: node.name.locationData.last_line, + last_column: node.name.locationData.last_column + }; + } + vars = getVars(node.name).concat(getVars(node.index)); + } else if (node.name) { + location = node.name.locationData; + vars = getVars(node.name); + } else if (node.index) { + location = node.index.locationData; + vars = getVars(node.index); + } else { + location = node.locationData; + vars = []; + } + before = this.createInstrumentedNode("before", { + location: location, + vars: vars + }); + after = this.createInstrumentedNode("after", { + location: location, + vars: vars, + functionCalls: [] + }); + if (node.guard) { + parensBlock = this.coffee.nodes("(0)").expressions[0]; + parensBlock.base.body.expressions = [before, after, node.guard]; + node.guard = parensBlock; + } else { + node.body.expressions.unshift(before, after); + } + } else if (node instanceof this.nodeTypes.While) { + node.condition = this.createInstrumentedExpr(node.condition); + if (node.guard) { + node.guard = this.createInstrumentedExpr(node.guard); + } } else if (node instanceof this.nodeTypes.Switch) { if (node.subject) { - node.subject = this.createInstrumentedExpr(node, "code", node.subject); + node.subject = this.createInstrumentedExpr(node.subject); } - ref = node.cases; - for (i = 0, len = ref.length; i < len; i++) { - caseClause = ref[i]; - if (caseClause[0] instanceof Array) { - caseClause[0][0] = this.createInstrumentedExpr(caseClause[0][0], "code", caseClause[0][0]); + ref2 = node.cases; + for (k = 0, len1 = ref2.length; k < len1; k++) { + caseClause = ref2[k]; + if (isArray(caseClause[0])) { + caseClause[0][0] = this.createInstrumentedExpr(caseClause[0][0]); } else { - caseClause[0] = this.createInstrumentedExpr(caseClause[0], "code", caseClause[0]); + caseClause[0] = this.createInstrumentedExpr(caseClause[0]); } } - return node.eachChild((function(_this) { - return function(child) { - return _this.instrumentTree(child, node); - }; - })(this)); } else if (node instanceof this.nodeTypes.If) { - node.condition = this.createInstrumentedExpr(node.condition, "code", node.condition); - return node.eachChild((function(_this) { - return function(child) { - return _this.instrumentTree(child, node); - }; - })(this)); + node.condition = this.createInstrumentedExpr(node.condition); + } else if (node instanceof this.nodeTypes.Class) { + before = this.createInstrumentedNode("before", { + node: node + }); + after = this.createInstrumentedNode("after", { + node: node + }); + node.body.expressions.unshift(before, after); + } else if (node instanceof this.nodeTypes.Try) { + if (node.recovery && node.errorVariable) { + if (node.errorVariable instanceof this.nodeTypes.Literal) { + vars = [node.errorVariable.value]; + } else { + vars = this.findVariables(node.errorVariable); + } + before = this.createInstrumentedNode("before", { + node: node.errorVariable, + vars: vars + }); + after = this.createInstrumentedNode("after", { + node: node.errorVariable, + vars: vars, + functionCalls: [] + }); + node.recovery.expressions.unshift(before, after); + } } else if (node instanceof this.nodeTypes.Code) { - tryBlock = this.coffee.nodes("try\nfinally"); - tryNode = tryBlock.expressions[0]; + returnOrThrowVar = this.temporaryVariable("returnOrThrow"); + block = this.coffee.nodes(returnOrThrowVar + " = { type: 'return', value: undefined }\ntry\ncatch " + this.caughtErrorVar + "\n " + returnOrThrowVar + ".type = 'throw'\n " + returnOrThrowVar + ".value = " + this.caughtErrorVar + "\n throw " + this.caughtErrorVar + "\nfinally"); + tryNode = block.expressions[1]; tryNode.attempt = node.body; - tryBlock.expressions.unshift(this.createInstrumentedNode(node, "enter")); - tryNode.ensure.expressions.unshift(this.createInstrumentedNode(node, "leave")); - node.body = tryBlock; - return this.instrumentTree(tryNode.attempt, tryNode); - } else { - node.eachChild((function(_this) { + block.expressions.unshift(this.createInstrumentedNode("enter", { + node: node + })); + tryNode.ensure.expressions.unshift(this.createInstrumentedNode("leave", { + node: node, + returnOrThrowVar: returnOrThrowVar + })); + node.body = block; + this.instrumentTree(tryNode.attempt, tryNode, inClass, returnOrThrowVar); + recursed = true; + } + if (!recursed) { + return this.mapChildren(node, (function(_this) { return function(child) { - return _this.instrumentTree(child, node); + var ret; + ret = child; + if (child.pencilTracerReturnVar) { + ret = _this.createAssignNode(child.pencilTracerReturnVar, child); + } + _this.instrumentTree(child, node, inClass, returnOrThrowVar); + return ret; }; })(this)); - if (node.icedContinuationBlock != null) { - return this.instrumentTree(node.icedContinuationBlock, node); - } } }; @@ -321,22 +634,20 @@ sourceMap: this.options.sourceMap, literate: this.options.literate }; - csOptions.referencedVars = (function() { - var i, len, ref, results; + this.referencedVars = csOptions.referencedVars = (function() { + var j, len, ref, results; ref = this.coffee.tokens(code, csOptions); results = []; - for (i = 0, len = ref.length; i < len; i++) { - token = ref[i]; + for (j = 0, len = ref.length; j < len; j++) { + token = ref[j]; if (token.variable) { results.push(token[1]); } } return results; }).call(this); + this.caughtErrorVar = this.temporaryVariable("err"); ast = this.coffee.nodes(code, csOptions); - if (this.options.trackVariables) { - this.findScopes(ast); - } this.instrumentTree(ast); if (this.options.ast) { return ast; @@ -360,7 +671,7 @@ }).call(this); -},{"./scope":4}],2:[function(require,module,exports){ +},{}],2:[function(require,module,exports){ // Generated by CoffeeScript 1.9.3 (function() { var instrumentCoffee, instrumentJs; @@ -378,4289 +689,10376 @@ },{"./coffeescript_instrumenter":1,"./javascript_instrumenter":3}],3:[function(require,module,exports){ // Generated by CoffeeScript 1.9.3 (function() { - var JavaScriptInstrumenter, STATEMENTS, STATEMENTS_WITH_BODIES, falafel, + var JavaScriptInstrumenter, acorn, escodegen, isArray, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - falafel = require("falafel"); + acorn = require("acorn"); - STATEMENTS = ["EmptyStatement", "BlockStatement", "ExpressionStatement", "IfStatement", "LabeledStatement", "BreakStatement", "ContinueStatement", "WithStatement", "SwitchStatement", "ReturnStatement", "ThrowStatement", "TryStatement", "WhileStatement", "DoWhileStatement", "ForStatement", "ForInStatement", "DebuggerStatement", "FunctionDeclaration", "VariableDeclaration"]; + escodegen = require("escodegen"); - STATEMENTS_WITH_BODIES = ["IfStatement", "LabeledStatement", "WithStatement", "WhileStatement", "DoWhileStatement", "ForStatement", "ForInStatement"]; + isArray = Array.isArray || function(value) { + return {}.toString.call(value) === '[object Array]'; + }; JavaScriptInstrumenter = (function() { - function JavaScriptInstrumenter() {} - - JavaScriptInstrumenter.prototype.traceCall = function(traceFunc, location, eventType) { - var locationObj; - locationObj = "{ first_line: " + location.start.line + ","; - locationObj += " first_column: " + (location.start.column + 1) + ","; - locationObj += " last_line: " + location.end.line + ","; - locationObj += " last_column: " + (location.end.column + 1) + " }"; - return traceFunc + "({ location: " + locationObj + ", type: '" + eventType + "' })"; - }; + function JavaScriptInstrumenter(options1) { + var base1; + this.options = options1; + if ((base1 = this.options).traceFunc == null) { + base1.traceFunc = "pencilTrace"; + } + } - JavaScriptInstrumenter.prototype.needsBraces = function(node) { - var ref, ref1; - return (ref = node.type, indexOf.call(STATEMENTS, ref) >= 0) && node.type !== "BlockStatement" && (ref1 = node.parent.type, indexOf.call(STATEMENTS_WITH_BODIES, ref1) >= 0) && !(node.parent.type === "ForStatement" && node.parent.init === node) && !(node.parent.type === "ForInStatement" && node.parent.left === node); + JavaScriptInstrumenter.prototype.temporaryVariable = function(base, needsDeclaration) { + var curName, index, name; + if (needsDeclaration == null) { + needsDeclaration = false; + } + name = "_penciltracer_" + base; + index = 0; + while (true) { + curName = name + index; + if (indexOf.call(this.referencedVars, curName) < 0) { + this.referencedVars.push(curName); + if (needsDeclaration) { + this.undeclaredVars.push(curName); + } + return curName; + } + index++; + } }; - JavaScriptInstrumenter.prototype.instrument = function(filename, code, options) { - var ref, result, traceFunc; + JavaScriptInstrumenter.prototype.createInstrumentedNode = function(eventType, options) { + var eventObj, extra, f, functionCalls, instrumentedNode, loc, locationObj, name, ref, ref1, ref2, soakify, vars; if (options == null) { options = {}; } - traceFunc = (ref = options.traceFunc) != null ? ref : "pencilTrace"; - result = falafel(code, { - locations: true - }, (function(_this) { - return function(node) { - var enter, leave, ref1, ref2, ref3, ref4, ref5, ref6; - switch (node.type) { - case "EmptyStatement": - case "ExpressionStatement": - case "BreakStatement": - case "ContinueStatement": - case "ReturnStatement": - case "ThrowStatement": - case "DebuggerStatement": - case "FunctionDeclaration": - code = _this.traceCall(traceFunc, node.loc, "code"); - node.update(code + "; " + (node.source())); - if ((ref1 = node.parent.type) === "DoWhileStatement" || ref1 === "ForInStatement") { - code = _this.traceCall(traceFunc, node.parent.loc, "code"); - node.update(code + "; " + (node.source())); - } - break; - case "VariableDeclaration": - if ((ref2 = node.parent.type) !== "ForStatement" && ref2 !== "ForInStatement") { - code = _this.traceCall(traceFunc, node.loc, "code"); - node.update(code + "; " + (node.source())); - } - break; - case "ForStatement": - code = _this.traceCall(traceFunc, ((ref3 = node.init) != null ? ref3.loc : void 0) || node.loc, "code"); - node.update(code + "; " + (node.source())); - break; - case "BlockStatement": - if ((ref4 = node.parent.type) === "FunctionDeclaration" || ref4 === "FunctionExpression") { - enter = _this.traceCall(traceFunc, node.loc, "enter"); - leave = _this.traceCall(traceFunc, node.loc, "leave"); - node.update("{ " + enter + "; try " + (node.source()) + " finally { " + leave + "; } }"); - } - if (node.parent.type === "TryStatement") { - if (node.parent.block === node) { - code = _this.traceCall(traceFunc, node.parent.loc, "code"); - node.update("{ " + code + "; " + (node.source()) + " }"); - } else if (node.parent.finalizer === node) { - code = _this.traceCall(traceFunc, node.loc, "code"); - node.update("{ " + code + "; " + (node.source()) + " }"); - } - } - if (node.parent.type === "CatchClause") { - code = _this.traceCall(traceFunc, node.parent.loc, "code"); - node.update("{ " + code + "; " + (node.source()) + " }"); - } - if ((ref5 = node.parent.type) === "DoWhileStatement" || ref5 === "ForInStatement") { - code = _this.traceCall(traceFunc, node.parent.loc, "code"); - node.update("{ " + code + "; " + (node.source()) + " }"); + loc = (ref = options.loc) != null ? ref : options.node.loc; + if (eventType !== "leave") { + vars = (ref1 = options.vars) != null ? ref1 : (eventType === "enter" ? this.findArguments(options.node) : this.findVariables(options.node)); + } + if (eventType === "after") { + functionCalls = (ref2 = options.functionCalls) != null ? ref2 : this.findFunctionCalls(options.node); + } + locationObj = "{ first_line: " + loc.start.line + ","; + locationObj += " first_column: " + (loc.start.column + 1) + ","; + locationObj += " last_line: " + loc.end.line + ","; + locationObj += " last_column: " + (loc.end.column + 1) + " }"; + soakify = function(name) { + if (name.indexOf(".") === -1) { + return "(typeof " + name + " === 'undefined' ? void 0 : " + name + ")"; + } else { + throw "todo"; + } + }; + extra = (function() { + switch (eventType) { + case "before": + case "after": + return "vars: [" + ((function() { + var j, len, results; + results = []; + for (j = 0, len = vars.length; j < len; j++) { + name = vars[j]; + results.push("{name: '" + name + "', value: " + (soakify(name)) + "}"); } - break; - case "ThisExpression": - case "ArrayExpression": - case "ObjectExpression": - case "FunctionExpression": - case "SequenceExpression": - case "UnaryExpression": - case "BinaryExpression": - case "AssignmentExpression": - case "UpdateExpression": - case "LogicalExpression": - case "ConditionalExpression": - case "CallExpression": - case "NewExpression": - case "MemberExpression": - case "Identifier": - case "Literal": - case "RegExpLiteral": - if ((ref6 = node.parent.type) === "IfStatement" || ref6 === "WithStatement" || ref6 === "SwitchStatement" || ref6 === "WhileStatement" || ref6 === "DoWhileStatement" || ref6 === "ForStatement" || ref6 === "SwitchCase") { - code = _this.traceCall(traceFunc, node.loc, "code"); - node.update(code + ",(" + (node.source()) + ")"); + return results; + })()) + "]"; + case "enter": + return "vars: [" + ((function() { + var j, len, results; + results = []; + for (j = 0, len = vars.length; j < len; j++) { + name = vars[j]; + results.push("{name: '" + name + "', value: " + name + "}"); } + return results; + })()) + "]"; + case "leave": + return "returnOrThrow: " + options.returnOrThrowVar; + } + })(); + if (eventType === "after") { + extra += ", functionCalls: [" + ((function() { + var j, len, results; + results = []; + for (j = 0, len = functionCalls.length; j < len; j++) { + f = functionCalls[j]; + results.push("{name: '" + f.name + "', value: " + f.tempVar + "}"); } - if (_this.needsBraces(node)) { - return node.update("{ " + (node.source()) + " }"); - } - }; - })(this)); - return result.toString(); + return results; + })()) + "]"; + } + eventObj = "{location: " + locationObj + ", type: '" + eventType + "', " + extra + "}"; + instrumentedNode = acorn.parse(this.options.traceFunc + "(" + eventObj + ");").body[0]; + instrumentedNode.pencilTracerInstrumented = true; + instrumentedNode.expression.pencilTracerInstrumented = true; + return instrumentedNode; }; - return JavaScriptInstrumenter; - - })(); - - exports.instrumentJs = function(filename, code, options) { - var instrumenter; - if (options == null) { - options = {}; - } - instrumenter = new JavaScriptInstrumenter(); - return instrumenter.instrument(filename, code, options); - }; - -}).call(this); - -},{"falafel":5}],4:[function(require,module,exports){ -// Generated by CoffeeScript 1.9.3 -(function() { - var Scope; + JavaScriptInstrumenter.prototype.createInstrumentedExpr = function(originalExpr) { + var sequenceExpr, tempVar; + tempVar = this.temporaryVariable("temp", true); + sequenceExpr = { + type: "SequenceExpression", + expressions: [] + }; + sequenceExpr.expressions.push(this.createInstrumentedNode("before", { + node: originalExpr + }).expression); + sequenceExpr.expressions.push(this.createAssignNode(tempVar, originalExpr)); + sequenceExpr.expressions.push(this.createInstrumentedNode("after", { + node: originalExpr + }).expression); + sequenceExpr.expressions.push({ + type: "Identifier", + name: tempVar + }); + return sequenceExpr; + }; - Scope = (function() { - function Scope(parent) { - this.parent = parent; - this.vars = []; - } + JavaScriptInstrumenter.prototype.createAssignNode = function(varName, expr) { + return { + type: "AssignmentExpression", + operator: "=", + left: { + type: "Identifier", + name: varName + }, + right: expr + }; + }; - Scope.prototype.add = function(variable, type) { - if (this.vars.indexOf(variable) === -1) { - return this.vars.push({ - name: variable, - type: type - }); + JavaScriptInstrumenter.prototype.findVariables = function(node, vars) { + var child, j, key, len, ref, ref1; + if (vars == null) { + vars = []; + } + if (node.type === "Identifier") { + if (vars.indexOf(node.name) === -1) { + vars.push(node.name); + } + } + for (key in node) { + if (node.type === "Property" && key === "key") { + continue; + } + if (((ref = node.type) === "FunctionExpression" || ref === "FunctionDeclaration") && key === "params") { + continue; + } + if (isArray(node[key])) { + ref1 = node[key]; + for (j = 0, len = ref1.length; j < len; j++) { + child = ref1[j]; + this.findVariables(child, vars); + } + } else if (node[key] && typeof node[key].type === "string") { + this.findVariables(node[key], vars); + } } + return vars; }; - Scope.prototype.toCode = function(activeVars) { - var code, curScope, i, isActive, len, ref, variable; - curScope = this; - code = "{"; - while (curScope) { - ref = curScope.vars; - for (i = 0, len = ref.length; i < len; i++) { - variable = ref[i]; - isActive = activeVars.indexOf(variable.name) !== -1; - code += "'" + variable.name + "': { name: '" + variable.name + "', value: " + variable.name + ", type: '" + variable.type + "', active: " + isActive + " }, "; - } - curScope = curScope.parent; + JavaScriptInstrumenter.prototype.findArguments = function(funcNode) { + var j, len, param, ref, results; + ref = funcNode.params; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + param = ref[j]; + results.push(param.name); } - code += "}"; - return code; + return results; }; - return Scope; - - })(); + JavaScriptInstrumenter.prototype.findFunctionCalls = function(node, parent, grandparent, vars) { + if (parent == null) { + parent = null; + } + if (grandparent == null) { + grandparent = null; + } + if (vars == null) { + vars = []; + } + return []; + }; - exports.Scope = Scope; + JavaScriptInstrumenter.prototype.shouldInstrumentWithBlock = function(node, parent) { + var ref; + return ((ref = node.type) === "EmptyStatement" || ref === "ExpressionStatement" || ref === "DebuggerStatement" || ref === "VariableDeclaration" || ref === "FunctionDeclaration") && !(parent.type === "ForStatement" && parent.init === node) && !(parent.type === "ForInStatement" && parent.left === node); + }; -}).call(this); + JavaScriptInstrumenter.prototype.shouldInstrumentExpr = function(node, parent) { + return (parent.type === "IfStatement" && parent.test === node) || (parent.type === "WithStatement" && parent.object === node) || (parent.type === "SwitchStatement" && parent.discriminant === node) || (parent.type === "WhileStatement" && parent.test === node) || (parent.type === "DoWhileStatement" && parent.test === node) || (parent.type === "ForStatement" && parent.test === node) || (parent.type === "ForStatement" && parent.update === node) || (parent.type === "SwitchCase" && parent.test === node); + }; -},{}],5:[function(require,module,exports){ -var parse = require('acorn').parse; - -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) keys.push(key); - return keys; -}; -var forEach = function (xs, fn) { - if (xs.forEach) return xs.forEach(fn); - for (var i = 0; i < xs.length; i++) { - fn.call(xs, xs[i], i, xs); - } -}; - -var isArray = Array.isArray || function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; -}; + JavaScriptInstrumenter.prototype.mapChildren = function(node, func) { + var child, i, key, results; + results = []; + for (key in node) { + if (isArray(node[key])) { + results.push((function() { + var j, len, ref, results1; + ref = node[key]; + results1 = []; + for (i = j = 0, len = ref.length; j < len; i = ++j) { + child = ref[i]; + results1.push(node[key][i] = func(child)); + } + return results1; + })()); + } else if (node[key] && node[key].type) { + results.push(node[key] = func(node[key])); + } else { + results.push(void 0); + } + } + return results; + }; -module.exports = function (src, opts, fn) { - if (typeof opts === 'function') { - fn = opts; - opts = {}; - } - if (typeof src === 'object') { - opts = src; - src = opts.source; - delete opts.source; - } - src = src === undefined ? opts.source : src; - if (typeof src !== 'string') src = String(src); - var ast = parse(src, opts); - - var result = { - chunks : src.split(''), - toString : function () { return result.chunks.join('') }, - inspect : function () { return result.toString() } + JavaScriptInstrumenter.prototype.instrumentTree = function(node, parent, returnOrThrowVar) { + var ref; + if (parent == null) { + parent = null; + } + if ((ref = node.type) === "FunctionDeclaration" || ref === "FunctionExpression") { + returnOrThrowVar = this.temporaryVariable("returnOrThrow"); + } + return this.mapChildren(node, (function(_this) { + return function(child) { + var newBlock, ref1, tryStatement; + _this.instrumentTree(child, node, returnOrThrowVar); + if (_this.shouldInstrumentWithBlock(child, node)) { + return { + type: "BlockStatement", + body: [ + _this.createInstrumentedNode("before", { + node: child + }), child, _this.createInstrumentedNode("after", { + node: child + }) + ] + }; + } else if (_this.shouldInstrumentExpr(child, node)) { + return _this.createInstrumentedExpr(child); + } else if (((ref1 = node.type) === "FunctionDeclaration" || ref1 === "FunctionExpression") && node.body === child) { + newBlock = acorn.parse("{\n var " + returnOrThrowVar + " = { type: 'return', value: void 0 };\n try {}\n catch (" + _this.caughtErrorVar + ") {\n " + returnOrThrowVar + ".type = 'throw';\n " + returnOrThrowVar + ".value = " + _this.caughtErrorVar + ";\n throw " + _this.caughtErrorVar + ";\n } finally {}\n}").body[0]; + tryStatement = newBlock.body[1]; + tryStatement.block = child; + newBlock.body.unshift(_this.createInstrumentedNode("enter", { + node: node + })); + tryStatement.finalizer.body.unshift(_this.createInstrumentedNode("leave", { + node: node, + returnOrThrowVar: returnOrThrowVar + })); + return newBlock; + } else { + return child; + } + }; + })(this)); }; - var index = 0; - - (function walk (node, parent) { - insertHelpers(node, parent, result.chunks); - - forEach(objectKeys(node), function (key) { - if (key === 'parent') return; - - var child = node[key]; - if (isArray(child)) { - forEach(child, function (c) { - if (c && typeof c.type === 'string') { - walk(c, node); - } - }); + + JavaScriptInstrumenter.prototype.instrument = function(filename, code) { + var ast, name, tempVarsDeclaration; + this.undeclaredVars = []; + this.referencedVars = []; + ast = acorn.parse(code, { + locations: true, + onToken: (function(_this) { + return function(token) { + if (token.type.label === "name" && _this.referencedVars.indexOf(token.value) === -1) { + return _this.referencedVars.push(token.value); } - else if (child && typeof child.type === 'string') { - walk(child, node); + }; + })(this) + }); + this.caughtErrorVar = this.temporaryVariable("err"); + this.instrumentTree(ast); + if (this.undeclaredVars.length > 0) { + tempVarsDeclaration = { + type: "VariableDeclaration", + kind: "var", + declarations: (function() { + var j, len, ref, results; + ref = this.undeclaredVars; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + name = ref[j]; + results.push({ + type: "VariableDeclarator", + id: { + type: "Identifier", + name: name + }, + init: null + }); } - }); - fn(node); - })(ast, undefined); - - return result; -}; - -function insertHelpers (node, parent, chunks) { - node.parent = parent; - - node.source = function () { - return chunks.slice(node.start, node.end).join(''); + return results; + }).call(this) + }; + ast.body.unshift(tempVarsDeclaration); + } + if (this.options.ast) { + return ast; + } + return escodegen.generate(ast); }; - - if (node.update && typeof node.update === 'object') { - var prev = node.update; - forEach(objectKeys(prev), function (key) { - update[key] = prev[key]; - }); - node.update = update; - } - else { - node.update = update; - } - - function update (s) { - chunks[node.start] = s; - for (var i = node.start + 1; i < node.end; i++) { - chunks[i] = ''; - } + + return JavaScriptInstrumenter; + + })(); + + exports.instrumentJs = function(filename, code, options) { + var instrumenter; + if (options == null) { + options = {}; } -} + instrumenter = new JavaScriptInstrumenter(options); + return instrumenter.instrument(filename, code); + }; + +}).call(this); -},{"acorn":6}],6:[function(require,module,exports){ +},{"acorn":4,"escodegen":7}],4:[function(require,module,exports){ (function (global){ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.acorn = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 6 && (prop.computed || prop.method || prop.shorthand)) return; + var key = prop.key, + name = undefined; + switch (key.type) { + case "Identifier": + name = key.name;break; + case "Literal": + name = String(key.value);break; + default: + return; + } + var kind = prop.kind; + if (this.options.ecmaVersion >= 6) { + if (name === "__proto__" && kind === "init") { + if (propHash.proto) this.raise(key.start, "Redefinition of __proto__ property"); + propHash.proto = true; + } + return; + } + var other = undefined; + if (_util.has(propHash, name)) { + other = propHash[name]; + var isGetSet = kind !== "init"; + if ((this.strict || isGetSet) && other[kind] || !(isGetSet ^ other.init)) this.raise(key.start, "Redefinition of property"); + } else { + other = propHash[name] = { + init: false, + get: false, + set: false + }; + } + other[kind] = true; +}; -_dereq_("./lval"); +// ### Expression parsing -_dereq_("./expression"); +// These nest, from the most general expression type at the top to +// 'atomic', nondivisible expression types at the bottom. Most of +// the functions will simply let the function(s) below them parse, +// and, *if* the syntactic construct they handle is present, wrap +// the AST node that the inner parser gave them in another node. -exports.Parser = _state.Parser; -exports.plugins = _state.plugins; -exports.defaultOptions = _options.defaultOptions; +// Parse a full expression. The optional arguments are used to +// forbid the `in` operator (in for loops initalization expressions) +// and provide reference for storing '=' operator inside shorthand +// property assignment in contexts where both object expression +// and object pattern might appear (so it's possible to raise +// delayed syntax error at correct position). -var _location = _dereq_("./location"); +pp.parseExpression = function (noIn, refShorthandDefaultPos) { + var startPos = this.start, + startLoc = this.startLoc; + var expr = this.parseMaybeAssign(noIn, refShorthandDefaultPos); + if (this.type === _tokentype.types.comma) { + var node = this.startNodeAt(startPos, startLoc); + node.expressions = [expr]; + while (this.eat(_tokentype.types.comma)) node.expressions.push(this.parseMaybeAssign(noIn, refShorthandDefaultPos)); + return this.finishNode(node, "SequenceExpression"); + } + return expr; +}; -exports.SourceLocation = _location.SourceLocation; -exports.getLineInfo = _location.getLineInfo; -exports.Node = _dereq_("./node").Node; +// Parse an assignment expression. This includes applications of +// operators like `+=`. -var _tokentype = _dereq_("./tokentype"); +pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse) { + if (this.type == _tokentype.types._yield && this.inGenerator) return this.parseYield(); -exports.TokenType = _tokentype.TokenType; -exports.tokTypes = _tokentype.types; + var failOnShorthandAssign = undefined; + if (!refShorthandDefaultPos) { + refShorthandDefaultPos = { start: 0 }; + failOnShorthandAssign = true; + } else { + failOnShorthandAssign = false; + } + var startPos = this.start, + startLoc = this.startLoc; + if (this.type == _tokentype.types.parenL || this.type == _tokentype.types.name) this.potentialArrowAt = this.start; + var left = this.parseMaybeConditional(noIn, refShorthandDefaultPos); + if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc); + if (this.type.isAssign) { + var node = this.startNodeAt(startPos, startLoc); + node.operator = this.value; + node.left = this.type === _tokentype.types.eq ? this.toAssignable(left) : left; + refShorthandDefaultPos.start = 0; // reset because shorthand default was used correctly + this.checkLVal(left); + this.next(); + node.right = this.parseMaybeAssign(noIn); + return this.finishNode(node, "AssignmentExpression"); + } else if (failOnShorthandAssign && refShorthandDefaultPos.start) { + this.unexpected(refShorthandDefaultPos.start); + } + return left; +}; -var _tokencontext = _dereq_("./tokencontext"); +// Parse a ternary conditional (`?:`) operator. -exports.TokContext = _tokencontext.TokContext; -exports.tokContexts = _tokencontext.types; +pp.parseMaybeConditional = function (noIn, refShorthandDefaultPos) { + var startPos = this.start, + startLoc = this.startLoc; + var expr = this.parseExprOps(noIn, refShorthandDefaultPos); + if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; + if (this.eat(_tokentype.types.question)) { + var node = this.startNodeAt(startPos, startLoc); + node.test = expr; + node.consequent = this.parseMaybeAssign(); + this.expect(_tokentype.types.colon); + node.alternate = this.parseMaybeAssign(noIn); + return this.finishNode(node, "ConditionalExpression"); + } + return expr; +}; -var _identifier = _dereq_("./identifier"); +// Start the precedence parser. -exports.isIdentifierChar = _identifier.isIdentifierChar; -exports.isIdentifierStart = _identifier.isIdentifierStart; -exports.Token = _dereq_("./tokenize").Token; +pp.parseExprOps = function (noIn, refShorthandDefaultPos) { + var startPos = this.start, + startLoc = this.startLoc; + var expr = this.parseMaybeUnary(refShorthandDefaultPos); + if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; + return this.parseExprOp(expr, startPos, startLoc, -1, noIn); +}; -var _whitespace = _dereq_("./whitespace"); +// Parse binary operators with the operator precedence parsing +// algorithm. `left` is the left-hand side of the operator. +// `minPrec` provides context that allows the function to stop and +// defer further parser to one of its callers when it encounters an +// operator that has a lower precedence than the set it is parsing. -exports.isNewLine = _whitespace.isNewLine; -exports.lineBreak = _whitespace.lineBreak; -exports.lineBreakG = _whitespace.lineBreakG; -var version = "1.2.2";exports.version = version; +pp.parseExprOp = function (left, leftStartPos, leftStartLoc, minPrec, noIn) { + var prec = this.type.binop; + if (prec != null && (!noIn || this.type !== _tokentype.types._in)) { + if (prec > minPrec) { + var node = this.startNodeAt(leftStartPos, leftStartLoc); + node.left = left; + node.operator = this.value; + var op = this.type; + this.next(); + var startPos = this.start, + startLoc = this.startLoc; + node.right = this.parseExprOp(this.parseMaybeUnary(), startPos, startLoc, prec, noIn); + this.finishNode(node, op === _tokentype.types.logicalOR || op === _tokentype.types.logicalAND ? "LogicalExpression" : "BinaryExpression"); + return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn); + } + } + return left; +}; -function parse(input, options) { - var p = parser(options, input); - var startPos = p.pos, - startLoc = p.options.locations && p.curPosition(); - p.nextToken(); - return p.parseTopLevel(p.options.program || p.startNodeAt(startPos, startLoc)); -} +// Parse unary operators, both prefix and postfix. -function parseExpressionAt(input, pos, options) { - var p = parser(options, input, pos); - p.nextToken(); - return p.parseExpression(); -} +pp.parseMaybeUnary = function (refShorthandDefaultPos) { + if (this.type.prefix) { + var node = this.startNode(), + update = this.type === _tokentype.types.incDec; + node.operator = this.value; + node.prefix = true; + this.next(); + node.argument = this.parseMaybeUnary(); + if (refShorthandDefaultPos && refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start); + if (update) this.checkLVal(node.argument);else if (this.strict && node.operator === "delete" && node.argument.type === "Identifier") this.raise(node.start, "Deleting local variable in strict mode"); + return this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression"); + } + var startPos = this.start, + startLoc = this.startLoc; + var expr = this.parseExprSubscripts(refShorthandDefaultPos); + if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; + while (this.type.postfix && !this.canInsertSemicolon()) { + var node = this.startNodeAt(startPos, startLoc); + node.operator = this.value; + node.prefix = false; + node.argument = expr; + this.checkLVal(expr); + this.next(); + expr = this.finishNode(node, "UpdateExpression"); + } + return expr; +}; -function tokenizer(input, options) { - return parser(options, input); -} +// Parse call, dot, and `[]`-subscript expressions. -function parser(options, input) { - return new Parser(getOptions(options), String(input)); -} +pp.parseExprSubscripts = function (refShorthandDefaultPos) { + var startPos = this.start, + startLoc = this.startLoc; + var expr = this.parseExprAtom(refShorthandDefaultPos); + if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; + return this.parseSubscripts(expr, startPos, startLoc); +}; -},{"./expression":6,"./identifier":7,"./location":8,"./lval":9,"./node":10,"./options":11,"./parseutil":12,"./state":13,"./statement":14,"./tokencontext":15,"./tokenize":16,"./tokentype":17,"./whitespace":19}],2:[function(_dereq_,module,exports){ -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor +pp.parseSubscripts = function (base, startPos, startLoc, noCalls) { + for (;;) { + if (this.eat(_tokentype.types.dot)) { + var node = this.startNodeAt(startPos, startLoc); + node.object = base; + node.property = this.parseIdent(true); + node.computed = false; + base = this.finishNode(node, "MemberExpression"); + } else if (this.eat(_tokentype.types.bracketL)) { + var node = this.startNodeAt(startPos, startLoc); + node.object = base; + node.property = this.parseExpression(); + node.computed = true; + this.expect(_tokentype.types.bracketR); + base = this.finishNode(node, "MemberExpression"); + } else if (!noCalls && this.eat(_tokentype.types.parenL)) { + var node = this.startNodeAt(startPos, startLoc); + node.callee = base; + node.arguments = this.parseExprList(_tokentype.types.parenR, false); + base = this.finishNode(node, "CallExpression"); + } else if (this.type === _tokentype.types.backQuote) { + var node = this.startNodeAt(startPos, startLoc); + node.tag = base; + node.quasi = this.parseTemplate(); + base = this.finishNode(node, "TaggedTemplateExpression"); + } else { + return base; + } } -} +}; -},{}],3:[function(_dereq_,module,exports){ -// shim for using process in browser +// Parse an atomic expression — either a single token that is an +// expression, an expression started by a keyword like `function` or +// `new`, or an expression wrapped in punctuation like `()`, `[]`, +// or `{}`. -var process = module.exports = {}; -var queue = []; -var draining = false; +pp.parseExprAtom = function (refShorthandDefaultPos) { + var node = undefined, + canBeArrow = this.potentialArrowAt == this.start; + switch (this.type) { + case _tokentype.types._super: + if (!this.inFunction) this.raise(this.start, "'super' outside of function or class"); + case _tokentype.types._this: + var type = this.type === _tokentype.types._this ? "ThisExpression" : "Super"; + node = this.startNode(); + this.next(); + return this.finishNode(node, type); -function drainQueue() { - if (draining) { - return; - } - draining = true; - var currentQueue; - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - var i = -1; - while (++i < len) { - currentQueue[i](); - } - len = queue.length; - } - draining = false; -} -process.nextTick = function (fun) { - queue.push(fun); - if (!draining) { - setTimeout(drainQueue, 0); - } -}; + case _tokentype.types._yield: + if (this.inGenerator) this.unexpected(); -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; + case _tokentype.types.name: + var startPos = this.start, + startLoc = this.startLoc; + var id = this.parseIdent(this.type !== _tokentype.types.name); + if (canBeArrow && !this.canInsertSemicolon() && this.eat(_tokentype.types.arrow)) return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id]); + return id; -function noop() {} + case _tokentype.types.regexp: + var value = this.value; + node = this.parseLiteral(value.value); + node.regex = { pattern: value.pattern, flags: value.flags }; + return node; -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; + case _tokentype.types.num:case _tokentype.types.string: + return this.parseLiteral(this.value); -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; + case _tokentype.types._null:case _tokentype.types._true:case _tokentype.types._false: + node = this.startNode(); + node.value = this.type === _tokentype.types._null ? null : this.type === _tokentype.types._true; + node.raw = this.type.keyword; + this.next(); + return this.finishNode(node, "Literal"); -// TODO(shtylman) -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; + case _tokentype.types.parenL: + return this.parseParenAndDistinguishExpression(canBeArrow); -},{}],4:[function(_dereq_,module,exports){ -module.exports = function isBuffer(arg) { - return arg && typeof arg === 'object' - && typeof arg.copy === 'function' - && typeof arg.fill === 'function' - && typeof arg.readUInt8 === 'function'; -} -},{}],5:[function(_dereq_,module,exports){ -(function (process,global){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. + case _tokentype.types.bracketL: + node = this.startNode(); + this.next(); + // check whether this is array comprehension or regular array + if (this.options.ecmaVersion >= 7 && this.type === _tokentype.types._for) { + return this.parseComprehension(node, false); + } + node.elements = this.parseExprList(_tokentype.types.bracketR, true, true, refShorthandDefaultPos); + return this.finishNode(node, "ArrayExpression"); -var formatRegExp = /%[sdj%]/g; -exports.format = function(f) { - if (!isString(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); - } - return objects.join(' '); - } + case _tokentype.types.braceL: + return this.parseObj(false, refShorthandDefaultPos); - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; - } - default: - return x; - } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); - } + case _tokentype.types._function: + node = this.startNode(); + this.next(); + return this.parseFunction(node, false); + + case _tokentype.types._class: + return this.parseClass(this.startNode(), false); + + case _tokentype.types._new: + return this.parseNew(); + + case _tokentype.types.backQuote: + return this.parseTemplate(); + + default: + this.unexpected(); } - return str; }; +pp.parseLiteral = function (value) { + var node = this.startNode(); + node.value = value; + node.raw = this.input.slice(this.start, this.end); + this.next(); + return this.finishNode(node, "Literal"); +}; + +pp.parseParenExpression = function () { + this.expect(_tokentype.types.parenL); + var val = this.parseExpression(); + this.expect(_tokentype.types.parenR); + return val; +}; -// Mark that a method should not be used. -// Returns a modified function which warns once by default. -// If --no-deprecation is set, then it is a no-op. -exports.deprecate = function(fn, msg) { - // Allow for deprecating things in the process of starting up. - if (isUndefined(global.process)) { - return function() { - return exports.deprecate(fn, msg).apply(this, arguments); - }; - } +pp.parseParenAndDistinguishExpression = function (canBeArrow) { + var startPos = this.start, + startLoc = this.startLoc, + val = undefined; + if (this.options.ecmaVersion >= 6) { + this.next(); - if (process.noDeprecation === true) { - return fn; - } + if (this.options.ecmaVersion >= 7 && this.type === _tokentype.types._for) { + return this.parseComprehension(this.startNodeAt(startPos, startLoc), true); + } - var warned = false; - function deprecated() { - if (!warned) { - if (process.throwDeprecation) { - throw new Error(msg); - } else if (process.traceDeprecation) { - console.trace(msg); + var innerStartPos = this.start, + innerStartLoc = this.startLoc; + var exprList = [], + first = true; + var refShorthandDefaultPos = { start: 0 }, + spreadStart = undefined, + innerParenStart = undefined; + while (this.type !== _tokentype.types.parenR) { + first ? first = false : this.expect(_tokentype.types.comma); + if (this.type === _tokentype.types.ellipsis) { + spreadStart = this.start; + exprList.push(this.parseParenItem(this.parseRest())); + break; } else { - console.error(msg); + if (this.type === _tokentype.types.parenL && !innerParenStart) { + innerParenStart = this.start; + } + exprList.push(this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem)); } - warned = true; } - return fn.apply(this, arguments); - } + var innerEndPos = this.start, + innerEndLoc = this.startLoc; + this.expect(_tokentype.types.parenR); - return deprecated; -}; + if (canBeArrow && !this.canInsertSemicolon() && this.eat(_tokentype.types.arrow)) { + if (innerParenStart) this.unexpected(innerParenStart); + return this.parseParenArrowList(startPos, startLoc, exprList); + } + if (!exprList.length) this.unexpected(this.lastTokStart); + if (spreadStart) this.unexpected(spreadStart); + if (refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start); -var debugs = {}; -var debugEnviron; -exports.debuglog = function(set) { - if (isUndefined(debugEnviron)) - debugEnviron = process.env.NODE_DEBUG || ''; - set = set.toUpperCase(); - if (!debugs[set]) { - if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { - var pid = process.pid; - debugs[set] = function() { - var msg = exports.format.apply(exports, arguments); - console.error('%s %d: %s', set, pid, msg); - }; + if (exprList.length > 1) { + val = this.startNodeAt(innerStartPos, innerStartLoc); + val.expressions = exprList; + this.finishNodeAt(val, "SequenceExpression", innerEndPos, innerEndLoc); } else { - debugs[set] = function() {}; + val = exprList[0]; } + } else { + val = this.parseParenExpression(); + } + + if (this.options.preserveParens) { + var par = this.startNodeAt(startPos, startLoc); + par.expression = val; + return this.finishNode(par, "ParenthesizedExpression"); + } else { + return val; } - return debugs[set]; }; +pp.parseParenItem = function (item) { + return item; +}; -/** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. - */ -/* legacy: obj, showHidden, depth, colors*/ -function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); -} -exports.inspect = inspect; - - -// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics -inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] -}; - -// Don't use 'blue' not visible on cmd.exe -inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' -}; - - -function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; - - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; - } -} - - -function stylizeNoColor(str, styleType) { - return str; -} - +pp.parseParenArrowList = function (startPos, startLoc, exprList) { + return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList); +}; -function arrayToHash(array) { - var hash = {}; +// New's precedence is slightly tricky. It must allow its argument +// to be a `[]` or dot subscript expression, but not a call — at +// least, not without wrapping it in parentheses. Thus, it uses the - array.forEach(function(val, idx) { - hash[val] = true; - }); +var empty = []; - return hash; -} +pp.parseNew = function () { + var node = this.startNode(); + var meta = this.parseIdent(true); + if (this.options.ecmaVersion >= 6 && this.eat(_tokentype.types.dot)) { + node.meta = meta; + node.property = this.parseIdent(true); + if (node.property.name !== "target") this.raise(node.property.start, "The only valid meta property for new is new.target"); + return this.finishNode(node, "MetaProperty"); + } + var startPos = this.start, + startLoc = this.startLoc; + node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true); + if (this.eat(_tokentype.types.parenL)) node.arguments = this.parseExprList(_tokentype.types.parenR, false);else node.arguments = empty; + return this.finishNode(node, "NewExpression"); +}; +// Parse template expression. -function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString(ret)) { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } +pp.parseTemplateElement = function () { + var elem = this.startNode(); + elem.value = { + raw: this.input.slice(this.start, this.end).replace(/\r\n?/g, "\n"), + cooked: this.value + }; + this.next(); + elem.tail = this.type === _tokentype.types.backQuote; + return this.finishNode(elem, "TemplateElement"); +}; - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; +pp.parseTemplate = function () { + var node = this.startNode(); + this.next(); + node.expressions = []; + var curElt = this.parseTemplateElement(); + node.quasis = [curElt]; + while (!curElt.tail) { + this.expect(_tokentype.types.dollarBraceL); + node.expressions.push(this.parseExpression()); + this.expect(_tokentype.types.braceR); + node.quasis.push(curElt = this.parseTemplateElement()); } + this.next(); + return this.finishNode(node, "TemplateLiteral"); +}; - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); +// Parse an object literal or binding pattern. - if (ctx.showHidden) { - keys = Object.getOwnPropertyNames(value); - } +pp.parseObj = function (isPattern, refShorthandDefaultPos) { + var node = this.startNode(), + first = true, + propHash = {}; + node.properties = []; + this.next(); + while (!this.eat(_tokentype.types.braceR)) { + if (!first) { + this.expect(_tokentype.types.comma); + if (this.afterTrailingComma(_tokentype.types.braceR)) break; + } else first = false; - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); + var prop = this.startNode(), + isGenerator = undefined, + startPos = undefined, + startLoc = undefined; + if (this.options.ecmaVersion >= 6) { + prop.method = false; + prop.shorthand = false; + if (isPattern || refShorthandDefaultPos) { + startPos = this.start; + startLoc = this.startLoc; + } + if (!isPattern) isGenerator = this.eat(_tokentype.types.star); + } + this.parsePropertyName(prop); + this.parsePropertyValue(prop, isPattern, isGenerator, startPos, startLoc, refShorthandDefaultPos); + this.checkPropClash(prop, propHash); + node.properties.push(this.finishNode(prop, "Property")); } + return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression"); +}; - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); +pp.parsePropertyValue = function (prop, isPattern, isGenerator, startPos, startLoc, refShorthandDefaultPos) { + if (this.eat(_tokentype.types.colon)) { + prop.value = isPattern ? this.parseMaybeDefault(this.start, this.startLoc) : this.parseMaybeAssign(false, refShorthandDefaultPos); + prop.kind = "init"; + } else if (this.options.ecmaVersion >= 6 && this.type === _tokentype.types.parenL) { + if (isPattern) this.unexpected(); + prop.kind = "init"; + prop.method = true; + prop.value = this.parseMethod(isGenerator); + } else if (this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" && (prop.key.name === "get" || prop.key.name === "set") && (this.type != _tokentype.types.comma && this.type != _tokentype.types.braceR)) { + if (isGenerator || isPattern) this.unexpected(); + prop.kind = prop.key.name; + this.parsePropertyName(prop); + prop.value = this.parseMethod(false); + var paramCount = prop.kind === "get" ? 0 : 1; + if (prop.value.params.length !== paramCount) { + var start = prop.value.start; + if (prop.kind === "get") this.raise(start, "getter should have no params");else this.raise(start, "setter should have exactly one param"); } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") { + prop.kind = "init"; + if (isPattern) { + if (this.isKeyword(prop.key.name) || this.strict && (_identifier.reservedWords.strictBind(prop.key.name) || _identifier.reservedWords.strict(prop.key.name)) || !this.options.allowReserved && this.isReservedWord(prop.key.name)) this.raise(prop.key.start, "Binding " + prop.key.name); + prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key); + } else if (this.type === _tokentype.types.eq && refShorthandDefaultPos) { + if (!refShorthandDefaultPos.start) refShorthandDefaultPos.start = this.start; + prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key); + } else { + prop.value = prop.key; } - if (isError(value)) { - return formatError(value); + prop.shorthand = true; + } else this.unexpected(); +}; + +pp.parsePropertyName = function (prop) { + if (this.options.ecmaVersion >= 6) { + if (this.eat(_tokentype.types.bracketL)) { + prop.computed = true; + prop.key = this.parseMaybeAssign(); + this.expect(_tokentype.types.bracketR); + return prop.key; + } else { + prop.computed = false; } } + return prop.key = this.type === _tokentype.types.num || this.type === _tokentype.types.string ? this.parseExprAtom() : this.parseIdent(true); +}; - var base = '', array = false, braces = ['{', '}']; - - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; - } +// Initialize empty function node. - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; +pp.initFunction = function (node) { + node.id = null; + if (this.options.ecmaVersion >= 6) { + node.generator = false; + node.expression = false; } +}; - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } +// Parse object or class method. - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); +pp.parseMethod = function (isGenerator) { + var node = this.startNode(); + this.initFunction(node); + this.expect(_tokentype.types.parenL); + node.params = this.parseBindingList(_tokentype.types.parenR, false, false); + var allowExpressionBody = undefined; + if (this.options.ecmaVersion >= 6) { + node.generator = isGenerator; } + this.parseFunctionBody(node, false); + return this.finishNode(node, "FunctionExpression"); +}; - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); - } +// Parse arrow function expression with given parameters. - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } +pp.parseArrowExpression = function (node, params) { + this.initFunction(node); + node.params = this.toAssignableList(params, true); + this.parseFunctionBody(node, true); + return this.finishNode(node, "ArrowFunctionExpression"); +}; - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } - } +// Parse function body and check parameters. - ctx.seen.push(value); +pp.parseFunctionBody = function (node, allowExpression) { + var isExpression = allowExpression && this.type !== _tokentype.types.braceL; - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + if (isExpression) { + node.body = this.parseMaybeAssign(); + node.expression = true; } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); + // Start a new scope with regard to labels and the `inFunction` + // flag (restore them to their old value afterwards). + var oldInFunc = this.inFunction, + oldInGen = this.inGenerator, + oldLabels = this.labels; + this.inFunction = true;this.inGenerator = node.generator;this.labels = []; + node.body = this.parseBlock(true); + node.expression = false; + this.inFunction = oldInFunc;this.inGenerator = oldInGen;this.labels = oldLabels; } - ctx.seen.pop(); + // If this is a strict mode function, verify that argument names + // are not repeated, and it does not try to bind the words `eval` + // or `arguments`. + if (this.strict || !isExpression && node.body.body.length && this.isUseStrict(node.body.body[0])) { + var nameHash = {}, + oldStrict = this.strict; + this.strict = true; + if (node.id) this.checkLVal(node.id, true); + for (var i = 0; i < node.params.length; i++) { + this.checkLVal(node.params[i], true, nameHash); + }this.strict = oldStrict; + } +}; - return reduceToSingleString(output, base, braces); -} +// Parses a comma-separated list of expressions, and returns them as +// an array. `close` is the token type that ends the list, and +// `allowEmpty` can be turned on to allow subsequent commas with +// nothing in between them to be parsed as `null` (which is needed +// for array literals). +pp.parseExprList = function (close, allowTrailingComma, allowEmpty, refShorthandDefaultPos) { + var elts = [], + first = true; + while (!this.eat(close)) { + if (!first) { + this.expect(_tokentype.types.comma); + if (allowTrailingComma && this.afterTrailingComma(close)) break; + } else first = false; -function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); + var elt = undefined; + if (allowEmpty && this.type === _tokentype.types.comma) elt = null;else if (this.type === _tokentype.types.ellipsis) elt = this.parseSpread(refShorthandDefaultPos);else elt = this.parseMaybeAssign(false, refShorthandDefaultPos); + elts.push(elt); } - if (isNumber(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); -} - - -function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; -} + return elts; +}; +// Parse the next token as an identifier. If `liberal` is true (used +// when parsing properties), it will also convert keywords into +// identifiers. -function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } +pp.parseIdent = function (liberal) { + var node = this.startNode(); + if (liberal && this.options.allowReserved == "never") liberal = false; + if (this.type === _tokentype.types.name) { + if (!liberal && (!this.options.allowReserved && this.isReservedWord(this.value) || this.strict && _identifier.reservedWords.strict(this.value) && (this.options.ecmaVersion >= 6 || this.input.slice(this.start, this.end).indexOf("\\") == -1))) this.raise(this.start, "The keyword '" + this.value + "' is reserved"); + node.name = this.value; + } else if (liberal && this.type.keyword) { + node.name = this.type.keyword; + } else { + this.unexpected(); } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; -} + this.next(); + return this.finishNode(node, "Identifier"); +}; +// Parses yield expression inside generator. -function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } +pp.parseYield = function () { + var node = this.startNode(); + this.next(); + if (this.type == _tokentype.types.semi || this.canInsertSemicolon() || this.type != _tokentype.types.star && !this.type.startsExpr) { + node.delegate = false; + node.argument = null; } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - if (!hasOwnProperty(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } + node.delegate = this.eat(_tokentype.types.star); + node.argument = this.parseMaybeAssign(); } + return this.finishNode(node, "YieldExpression"); +}; - return name + ': ' + str; -} - +// Parses array and generator comprehensions. -function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); - - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; +pp.parseComprehension = function (node, isGenerator) { + node.blocks = []; + while (this.type === _tokentype.types._for) { + var block = this.startNode(); + this.next(); + this.expect(_tokentype.types.parenL); + block.left = this.parseBindingAtom(); + this.checkLVal(block.left, true); + this.expectContextual("of"); + block.right = this.parseExpression(); + this.expect(_tokentype.types.parenR); + node.blocks.push(this.finishNode(block, "ComprehensionBlock")); } + node.filter = this.eat(_tokentype.types._if) ? this.parseParenExpression() : null; + node.body = this.parseExpression(); + this.expect(isGenerator ? _tokentype.types.parenR : _tokentype.types.bracketR); + node.generator = isGenerator; + return this.finishNode(node, "ComprehensionExpression"); +}; - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; -} +},{"./identifier":2,"./state":10,"./tokentype":14,"./util":15}],2:[function(_dereq_,module,exports){ +// This is a trick taken from Esprima. It turns out that, on +// non-Chrome browsers, to check whether a string is in a set, a +// predicate containing a big ugly `switch` statement is faster than +// a regular expression, and on Chrome the two are about on par. +// This function uses `eval` (non-lexical) to produce such a +// predicate from a space-separated string of words. +// +// It starts by sorting the words by length. +"use strict"; -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. -function isArray(ar) { - return Array.isArray(ar); -} -exports.isArray = isArray; +exports.__esModule = true; +exports.isIdentifierStart = isIdentifierStart; +exports.isIdentifierChar = isIdentifierChar; +function makePredicate(words) { + words = words.split(" "); + var f = "", + cats = []; + out: for (var i = 0; i < words.length; ++i) { + for (var j = 0; j < cats.length; ++j) { + if (cats[j][0].length == words[i].length) { + cats[j].push(words[i]); + continue out; + } + }cats.push([words[i]]); + } + function compareTo(arr) { + if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";"; + f += "switch(str){"; + for (var i = 0; i < arr.length; ++i) { + f += "case " + JSON.stringify(arr[i]) + ":"; + }f += "return true}return false;"; + } -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; + // When there are more than three length categories, an outer + // switch first dispatches on the lengths, to save on comparisons. -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; + if (cats.length > 3) { + cats.sort(function (a, b) { + return b.length - a.length; + }); + f += "switch(str.length){"; + for (var i = 0; i < cats.length; ++i) { + var cat = cats[i]; + f += "case " + cat[0].length + ":"; + compareTo(cat); + } + f += "}" -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; + // Otherwise, simply generate a flat `switch` statement. -function isNumber(arg) { - return typeof arg === 'number'; + ; + } else { + compareTo(words); + } + return new Function("str", f); } -exports.isNumber = isNumber; -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; +// Reserved word lists for various dialects of the language -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; +var reservedWords = { + 3: makePredicate("abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile"), + 5: makePredicate("class enum extends super const export import"), + 6: makePredicate("enum await"), + strict: makePredicate("implements interface let package private protected public static yield"), + strictBind: makePredicate("eval arguments") +}; -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; +exports.reservedWords = reservedWords; +// And the keywords -function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; +var ecma5AndLessKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this"; -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -exports.isObject = isObject; +var keywords = { + 5: makePredicate(ecma5AndLessKeywords), + 6: makePredicate(ecma5AndLessKeywords + " let const class extends export import yield super") +}; -function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; +exports.keywords = keywords; +// ## Character categories -function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; +// Big ugly regular expressions that match characters in the +// whitespace, identifier, and identifier-start categories. These +// are only applied when a character is found to actually have a +// code point above 128. +// Generated by `tools/generate-identifier-regex.js`. -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; - -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; +var nonASCIIidentifierStartChars = "ªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽͿΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠ-ࢲऄ-हऽॐक़-ॡॱ-ঀঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-హఽౘౙౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൠൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛮ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᧁ-ᧇᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕ℘-ℝℤΩℨK-ℹℼ-ℿⅅ-ⅉⅎⅠ-ↈⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞ々-〇〡-〩〱-〵〸-〼ぁ-ゖ゛-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚝꚠ-ꛯꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞭꞰꞱꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꩾ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭟꭤꭥꯀ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ"; +var nonASCIIidentifierChars = "‌‍·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-٩ٰۖ-ۜ۟-۪ۤۧۨ-ۭ۰-۹ܑܰ-݊ަ-ް߀-߉߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣤ-ःऺ-़ा-ॏ॑-ॗॢॣ०-९ঁ-ঃ়া-ৄেৈো-্ৗৢৣ০-৯ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑ੦-ੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣ૦-૯ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣ୦-୯ஂா-ூெ-ைொ-்ௗ௦-௯ఀ-ఃా-ౄె-ైొ-్ౕౖౢౣ౦-౯ಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣ೦-೯ഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣ൦-൯ංඃ්ා-ුූෘ-ෟ෦-෯ෲෳัิ-ฺ็-๎๐-๙ັິ-ູົຼ່-ໍ໐-໙༘༙༠-༩༹༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှ၀-၉ၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏ-ႝ፝-፟፩-፱ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝០-៩᠋-᠍᠐-᠙ᢩᤠ-ᤫᤰ-᤻᥆-᥏ᦰ-ᧀᧈᧉ᧐-᧚ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼-᪉᪐-᪙᪰-᪽ᬀ-ᬄ᬴-᭄᭐-᭙᭫-᭳ᮀ-ᮂᮡ-ᮭ᮰-᮹᯦-᯳ᰤ-᰷᱀-᱉᱐-᱙᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷼-᷿‿⁀⁔⃐-⃥⃜⃡-⃰⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꘠-꘩꙯ꙴ-꙽ꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-꣄꣐-꣙꣠-꣱꤀-꤉ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀꧐-꧙ꧥ꧰-꧹ꨩ-ꨶꩃꩌꩍ꩐-꩙ꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭꯰-꯹ﬞ︀-️︠-︭︳︴﹍-﹏0-9_"; -exports.isBuffer = _dereq_('./support/isBuffer'); +var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]"); +var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]"); -function objectToString(o) { - return Object.prototype.toString.call(o); -} +nonASCIIidentifierStartChars = nonASCIIidentifierChars = null; +// These are a run-length and offset encoded representation of the +// >0xffff code points that are a valid part of identifiers. The +// offset starts at 0x10000, and each pair of numbers represents an +// offset to the next range, and then a size of the range. They were +// generated by tools/generate-identifier-regex.js +var astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 17, 26, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 99, 39, 9, 51, 157, 310, 10, 21, 11, 7, 153, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 98, 21, 11, 25, 71, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 26, 45, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 955, 52, 76, 44, 33, 24, 27, 35, 42, 34, 4, 0, 13, 47, 15, 3, 22, 0, 38, 17, 2, 24, 133, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 32, 4, 287, 47, 21, 1, 2, 0, 185, 46, 82, 47, 21, 0, 60, 42, 502, 63, 32, 0, 449, 56, 1288, 920, 104, 110, 2962, 1070, 13266, 568, 8, 30, 114, 29, 19, 47, 17, 3, 32, 20, 6, 18, 881, 68, 12, 0, 67, 12, 16481, 1, 3071, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 4149, 196, 1340, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42710, 42, 4148, 12, 221, 16355, 541]; +var astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 1306, 2, 54, 14, 32, 9, 16, 3, 46, 10, 54, 9, 7, 2, 37, 13, 2, 9, 52, 0, 13, 2, 49, 13, 16, 9, 83, 11, 168, 11, 6, 9, 8, 2, 57, 0, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 316, 19, 13, 9, 214, 6, 3, 8, 112, 16, 16, 9, 82, 12, 9, 9, 535, 9, 20855, 9, 135, 4, 60, 6, 26, 9, 1016, 45, 17, 3, 19723, 1, 5319, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 4305, 6, 792618, 239]; -function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); +// This has a complexity linear to the value of the code. The +// assumption is that looking up astral identifier characters is +// rare. +function isInAstralSet(code, set) { + var pos = 0x10000; + for (var i = 0; i < set.length; i += 2) { + pos += set[i]; + if (pos > code) return false; + pos += set[i + 1]; + if (pos >= code) return true; + } } +// Test whether a given character code starts an identifier. + +function isIdentifierStart(code, astral) { + if (code < 65) return code === 36; + if (code < 91) return true; + if (code < 97) return code === 95; + if (code < 123) return true; + if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code)); + if (astral === false) return false; + return isInAstralSet(code, astralIdentifierStartCodes); +} -var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; +// Test whether a given character is part of an identifier. -// 26 Feb 16:19:34 -function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); +function isIdentifierChar(code, astral) { + if (code < 48) return code === 36; + if (code < 58) return true; + if (code < 65) return false; + if (code < 91) return true; + if (code < 97) return code === 95; + if (code < 123) return true; + if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code)); + if (astral === false) return false; + return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes); } +},{}],3:[function(_dereq_,module,exports){ +// Acorn is a tiny, fast JavaScript parser written in JavaScript. +// +// Acorn was written by Marijn Haverbeke, Ingvar Stepanyan, and +// various contributors and released under an MIT license. +// +// Git repositories for Acorn are available at +// +// http://marijnhaverbeke.nl/git/acorn +// https://github.com/marijnh/acorn.git +// +// Please use the [github bug tracker][ghbt] to report issues. +// +// [ghbt]: https://github.com/marijnh/acorn/issues +// +// This file defines the main parser interface. The library also comes +// with a [error-tolerant parser][dammit] and an +// [abstract syntax tree walker][walk], defined in other files. +// +// [dammit]: acorn_loose.js +// [walk]: util/walk.js -// log is just a thin wrapper to console.log that prepends a timestamp -exports.log = function() { - console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); -}; +"use strict"; +exports.__esModule = true; +exports.parse = parse; +exports.parseExpressionAt = parseExpressionAt; +exports.tokenizer = tokenizer; -/** - * Inherit the prototype methods from one constructor into another. - * - * The Function.prototype.inherits from lang.js rewritten as a standalone - * function (not on Function.prototype). NOTE: If this file is to be loaded - * during bootstrapping this function needs to be rewritten using some native - * functions as prototype setup using normal JavaScript does not work as - * expected during bootstrapping (see mirror.js in r114903). - * - * @param {function} ctor Constructor function which needs to inherit the - * prototype. - * @param {function} superCtor Constructor function to inherit prototype from. - */ -exports.inherits = _dereq_('inherits'); +var _state = _dereq_("./state"); -exports._extend = function(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; +var _options = _dereq_("./options"); - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; -}; +_dereq_("./parseutil"); -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} +_dereq_("./statement"); -}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./support/isBuffer":4,"_process":3,"inherits":2}],6:[function(_dereq_,module,exports){ -// A recursive descent parser operates by defining functions for all -// syntactic elements, and recursively calling those, each function -// advancing the input stream and returning an AST node. Precedence -// of constructs (for example, the fact that `!x[1]` means `!(x[1])` -// instead of `(!x)[1]` is handled by the fact that the parser -// function that parses unary prefix operators is called first, and -// in turn calls the function that parses `[]` subscripts — that -// way, it'll receive the node for `x[1]` already parsed, and wraps -// *that* in the unary operator node. -// -// Acorn uses an [operator precedence parser][opp] to handle binary -// operator precedence, because it is much more compact than using -// the technique outlined above, which uses different, nesting -// functions to specify precedence, for all of the ten binary -// precedence levels that JavaScript defines. -// -// [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser +_dereq_("./lval"); -"use strict"; +_dereq_("./expression"); -var tt = _dereq_("./tokentype").types; +_dereq_("./location"); -var Parser = _dereq_("./state").Parser; +exports.Parser = _state.Parser; +exports.plugins = _state.plugins; +exports.defaultOptions = _options.defaultOptions; -var reservedWords = _dereq_("./identifier").reservedWords; +var _locutil = _dereq_("./locutil"); -var has = _dereq_("./util").has; +exports.Position = _locutil.Position; +exports.SourceLocation = _locutil.SourceLocation; +exports.getLineInfo = _locutil.getLineInfo; -var pp = Parser.prototype; +var _node = _dereq_("./node"); -// Check if property name clashes with already added. -// Object/class getters and setters are not allowed to clash — -// either with each other or with an init property — and in -// strict mode, init properties are also not allowed to be repeated. +exports.Node = _node.Node; -pp.checkPropClash = function (prop, propHash) { - if (this.options.ecmaVersion >= 6) return; - var key = prop.key, - name = undefined; - switch (key.type) { - case "Identifier": - name = key.name;break; - case "Literal": - name = String(key.value);break; - default: - return; - } - var kind = prop.kind || "init", - other = undefined; - if (has(propHash, name)) { - other = propHash[name]; - var isGetSet = kind !== "init"; - if ((this.strict || isGetSet) && other[kind] || !(isGetSet ^ other.init)) this.raise(key.start, "Redefinition of property"); - } else { - other = propHash[name] = { - init: false, - get: false, - set: false - }; - } - other[kind] = true; -}; +var _tokentype = _dereq_("./tokentype"); -// ### Expression parsing +exports.TokenType = _tokentype.TokenType; +exports.tokTypes = _tokentype.types; -// These nest, from the most general expression type at the top to -// 'atomic', nondivisible expression types at the bottom. Most of -// the functions will simply let the function(s) below them parse, -// and, *if* the syntactic construct they handle is present, wrap -// the AST node that the inner parser gave them in another node. +var _tokencontext = _dereq_("./tokencontext"); -// Parse a full expression. The optional arguments are used to -// forbid the `in` operator (in for loops initalization expressions) -// and provide reference for storing '=' operator inside shorthand -// property assignment in contexts where both object expression -// and object pattern might appear (so it's possible to raise -// delayed syntax error at correct position). +exports.TokContext = _tokencontext.TokContext; +exports.tokContexts = _tokencontext.types; -pp.parseExpression = function (noIn, refShorthandDefaultPos) { - var startPos = this.start, - startLoc = this.startLoc; - var expr = this.parseMaybeAssign(noIn, refShorthandDefaultPos); - if (this.type === tt.comma) { - var node = this.startNodeAt(startPos, startLoc); - node.expressions = [expr]; - while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(noIn, refShorthandDefaultPos)); - return this.finishNode(node, "SequenceExpression"); - } - return expr; -}; +var _identifier = _dereq_("./identifier"); -// Parse an assignment expression. This includes applications of -// operators like `+=`. +exports.isIdentifierChar = _identifier.isIdentifierChar; +exports.isIdentifierStart = _identifier.isIdentifierStart; -pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse) { - if (this.type == tt._yield && this.inGenerator) return this.parseYield(); +var _tokenize = _dereq_("./tokenize"); - var failOnShorthandAssign = undefined; - if (!refShorthandDefaultPos) { - refShorthandDefaultPos = { start: 0 }; - failOnShorthandAssign = true; - } else { - failOnShorthandAssign = false; - } - var startPos = this.start, - startLoc = this.startLoc; - if (this.type == tt.parenL || this.type == tt.name) this.potentialArrowAt = this.start; - var left = this.parseMaybeConditional(noIn, refShorthandDefaultPos); - if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc); - if (this.type.isAssign) { - var node = this.startNodeAt(startPos, startLoc); - node.operator = this.value; - node.left = this.type === tt.eq ? this.toAssignable(left) : left; - refShorthandDefaultPos.start = 0; // reset because shorthand default was used correctly - this.checkLVal(left); - this.next(); - node.right = this.parseMaybeAssign(noIn); - return this.finishNode(node, "AssignmentExpression"); - } else if (failOnShorthandAssign && refShorthandDefaultPos.start) { - this.unexpected(refShorthandDefaultPos.start); - } - return left; -}; +exports.Token = _tokenize.Token; -// Parse a ternary conditional (`?:`) operator. +var _whitespace = _dereq_("./whitespace"); -pp.parseMaybeConditional = function (noIn, refShorthandDefaultPos) { - var startPos = this.start, - startLoc = this.startLoc; - var expr = this.parseExprOps(noIn, refShorthandDefaultPos); - if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; - if (this.eat(tt.question)) { - var node = this.startNodeAt(startPos, startLoc); - node.test = expr; - node.consequent = this.parseMaybeAssign(); - this.expect(tt.colon); - node.alternate = this.parseMaybeAssign(noIn); - return this.finishNode(node, "ConditionalExpression"); - } - return expr; -}; +exports.isNewLine = _whitespace.isNewLine; +exports.lineBreak = _whitespace.lineBreak; +exports.lineBreakG = _whitespace.lineBreakG; +var version = "2.1.0"; -// Start the precedence parser. +exports.version = version; +// The main exported interface (under `self.acorn` when in the +// browser) is a `parse` function that takes a code string and +// returns an abstract syntax tree as specified by [Mozilla parser +// API][api]. +// +// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API -pp.parseExprOps = function (noIn, refShorthandDefaultPos) { - var startPos = this.start, - startLoc = this.startLoc; - var expr = this.parseMaybeUnary(refShorthandDefaultPos); - if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; - return this.parseExprOp(expr, startPos, startLoc, -1, noIn); -}; +function parse(input, options) { + return new _state.Parser(options, input).parse(); +} -// Parse binary operators with the operator precedence parsing -// algorithm. `left` is the left-hand side of the operator. -// `minPrec` provides context that allows the function to stop and -// defer further parser to one of its callers when it encounters an -// operator that has a lower precedence than the set it is parsing. +// This function tries to parse a single expression at a given +// offset in a string. Useful for parsing mixed-language formats +// that embed JavaScript expressions. -pp.parseExprOp = function (left, leftStartPos, leftStartLoc, minPrec, noIn) { - var prec = this.type.binop; - if (Array.isArray(leftStartPos)) { - if (this.options.locations && noIn === undefined) { - // shift arguments to left by one - noIn = minPrec; - minPrec = leftStartLoc; - // flatten leftStartPos - leftStartLoc = leftStartPos[1]; - leftStartPos = leftStartPos[0]; - } - } - if (prec != null && (!noIn || this.type !== tt._in)) { - if (prec > minPrec) { - var node = this.startNodeAt(leftStartPos, leftStartLoc); - node.left = left; - node.operator = this.value; - var op = this.type; - this.next(); - var startPos = this.start, - startLoc = this.startLoc; - node.right = this.parseExprOp(this.parseMaybeUnary(), startPos, startLoc, prec, noIn); - this.finishNode(node, op === tt.logicalOR || op === tt.logicalAND ? "LogicalExpression" : "BinaryExpression"); - return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn); - } - } - return left; -}; +function parseExpressionAt(input, pos, options) { + var p = new _state.Parser(options, input, pos); + p.nextToken(); + return p.parseExpression(); +} -// Parse unary operators, both prefix and postfix. +// Acorn is organized as a tokenizer and a recursive-descent parser. +// The `tokenize` export provides an interface to the tokenizer. -pp.parseMaybeUnary = function (refShorthandDefaultPos) { - if (this.type.prefix) { - var node = this.startNode(), - update = this.type === tt.incDec; - node.operator = this.value; - node.prefix = true; - this.next(); - node.argument = this.parseMaybeUnary(); - if (refShorthandDefaultPos && refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start); - if (update) this.checkLVal(node.argument);else if (this.strict && node.operator === "delete" && node.argument.type === "Identifier") this.raise(node.start, "Deleting local variable in strict mode"); - return this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression"); - } - var startPos = this.start, - startLoc = this.startLoc; - var expr = this.parseExprSubscripts(refShorthandDefaultPos); - if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; - while (this.type.postfix && !this.canInsertSemicolon()) { - var node = this.startNodeAt(startPos, startLoc); - node.operator = this.value; - node.prefix = false; - node.argument = expr; - this.checkLVal(expr); - this.next(); - expr = this.finishNode(node, "UpdateExpression"); - } - return expr; -}; +function tokenizer(input, options) { + return new _state.Parser(options, input); +} -// Parse call, dot, and `[]`-subscript expressions. +},{"./expression":1,"./identifier":2,"./location":4,"./locutil":5,"./lval":6,"./node":7,"./options":8,"./parseutil":9,"./state":10,"./statement":11,"./tokencontext":12,"./tokenize":13,"./tokentype":14,"./whitespace":16}],4:[function(_dereq_,module,exports){ +"use strict"; -pp.parseExprSubscripts = function (refShorthandDefaultPos) { - var startPos = this.start, - startLoc = this.startLoc; - var expr = this.parseExprAtom(refShorthandDefaultPos); - if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; - return this.parseSubscripts(expr, startPos, startLoc); +var _state = _dereq_("./state"); + +var _locutil = _dereq_("./locutil"); + +var pp = _state.Parser.prototype; + +// This function is used to raise exceptions on parse errors. It +// takes an offset integer (into the current `input`) to indicate +// the location of the error, attaches the position to the end +// of the error message, and then raises a `SyntaxError` with that +// message. + +pp.raise = function (pos, message) { + var loc = _locutil.getLineInfo(this.input, pos); + message += " (" + loc.line + ":" + loc.column + ")"; + var err = new SyntaxError(message); + err.pos = pos;err.loc = loc;err.raisedAt = this.pos; + throw err; }; -pp.parseSubscripts = function (base, startPos, startLoc, noCalls) { - if (Array.isArray(startPos)) { - if (this.options.locations && noCalls === undefined) { - // shift arguments to left by one - noCalls = startLoc; - // flatten startPos - startLoc = startPos[1]; - startPos = startPos[0]; - } - } - for (;;) { - if (this.eat(tt.dot)) { - var node = this.startNodeAt(startPos, startLoc); - node.object = base; - node.property = this.parseIdent(true); - node.computed = false; - base = this.finishNode(node, "MemberExpression"); - } else if (this.eat(tt.bracketL)) { - var node = this.startNodeAt(startPos, startLoc); - node.object = base; - node.property = this.parseExpression(); - node.computed = true; - this.expect(tt.bracketR); - base = this.finishNode(node, "MemberExpression"); - } else if (!noCalls && this.eat(tt.parenL)) { - var node = this.startNodeAt(startPos, startLoc); - node.callee = base; - node.arguments = this.parseExprList(tt.parenR, false); - base = this.finishNode(node, "CallExpression"); - } else if (this.type === tt.backQuote) { - var node = this.startNodeAt(startPos, startLoc); - node.tag = base; - node.quasi = this.parseTemplate(); - base = this.finishNode(node, "TaggedTemplateExpression"); - } else { - return base; - } +pp.curPosition = function () { + if (this.options.locations) { + return new _locutil.Position(this.curLine, this.pos - this.lineStart); } }; -// Parse an atomic expression — either a single token that is an -// expression, an expression started by a keyword like `function` or -// `new`, or an expression wrapped in punctuation like `()`, `[]`, -// or `{}`. +},{"./locutil":5,"./state":10}],5:[function(_dereq_,module,exports){ +"use strict"; -pp.parseExprAtom = function (refShorthandDefaultPos) { - var node = undefined, - canBeArrow = this.potentialArrowAt == this.start; - switch (this.type) { - case tt._this: - case tt._super: - var type = this.type === tt._this ? "ThisExpression" : "Super"; - node = this.startNode(); - this.next(); - return this.finishNode(node, type); +exports.__esModule = true; +exports.getLineInfo = getLineInfo; - case tt._yield: - if (this.inGenerator) this.unexpected(); +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - case tt.name: - var startPos = this.start, - startLoc = this.startLoc; - var id = this.parseIdent(this.type !== tt.name); - if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id]); - return id; +var _whitespace = _dereq_("./whitespace"); - case tt.regexp: - var value = this.value; - node = this.parseLiteral(value.value); - node.regex = { pattern: value.pattern, flags: value.flags }; - return node; +// These are used when `options.locations` is on, for the +// `startLoc` and `endLoc` properties. - case tt.num:case tt.string: - return this.parseLiteral(this.value); +var Position = (function () { + function Position(line, col) { + _classCallCheck(this, Position); - case tt._null:case tt._true:case tt._false: - node = this.startNode(); - node.value = this.type === tt._null ? null : this.type === tt._true; - node.raw = this.type.keyword; - this.next(); - return this.finishNode(node, "Literal"); + this.line = line; + this.column = col; + } - case tt.parenL: - return this.parseParenAndDistinguishExpression(canBeArrow); + Position.prototype.offset = function offset(n) { + return new Position(this.line, this.column + n); + }; - case tt.bracketL: - node = this.startNode(); - this.next(); - // check whether this is array comprehension or regular array - if (this.options.ecmaVersion >= 7 && this.type === tt._for) { - return this.parseComprehension(node, false); - } - node.elements = this.parseExprList(tt.bracketR, true, true, refShorthandDefaultPos); - return this.finishNode(node, "ArrayExpression"); + return Position; +})(); - case tt.braceL: - return this.parseObj(false, refShorthandDefaultPos); +exports.Position = Position; - case tt._function: - node = this.startNode(); - this.next(); - return this.parseFunction(node, false); +var SourceLocation = function SourceLocation(p, start, end) { + _classCallCheck(this, SourceLocation); - case tt._class: - return this.parseClass(this.startNode(), false); + this.start = start; + this.end = end; + if (p.sourceFile !== null) this.source = p.sourceFile; +}; - case tt._new: - return this.parseNew(); +exports.SourceLocation = SourceLocation; - case tt.backQuote: - return this.parseTemplate(); +// The `getLineInfo` function is mostly useful when the +// `locations` option is off (for performance reasons) and you +// want to find the line/column position for a given character +// offset. `input` should be the code string that the offset refers +// into. - default: - this.unexpected(); +function getLineInfo(input, offset) { + for (var line = 1, cur = 0;;) { + _whitespace.lineBreakG.lastIndex = cur; + var match = _whitespace.lineBreakG.exec(input); + if (match && match.index < offset) { + ++line; + cur = match.index + match[0].length; + } else { + return new Position(line, offset - cur); + } } -}; +} -pp.parseLiteral = function (value) { - var node = this.startNode(); - node.value = value; - node.raw = this.input.slice(this.start, this.end); - this.next(); - return this.finishNode(node, "Literal"); -}; +},{"./whitespace":16}],6:[function(_dereq_,module,exports){ +"use strict"; -pp.parseParenExpression = function () { - this.expect(tt.parenL); - var val = this.parseExpression(); - this.expect(tt.parenR); - return val; -}; +var _tokentype = _dereq_("./tokentype"); -pp.parseParenAndDistinguishExpression = function (canBeArrow) { - var startPos = this.start, - startLoc = this.startLoc, - val = undefined; - if (this.options.ecmaVersion >= 6) { - this.next(); +var _state = _dereq_("./state"); - if (this.options.ecmaVersion >= 7 && this.type === tt._for) { - return this.parseComprehension(this.startNodeAt(startPos, startLoc), true); - } +var _identifier = _dereq_("./identifier"); - var innerStartPos = this.start, - innerStartLoc = this.startLoc; - var exprList = [], - first = true; - var refShorthandDefaultPos = { start: 0 }, - spreadStart = undefined, - innerParenStart = undefined; - while (this.type !== tt.parenR) { - first ? first = false : this.expect(tt.comma); - if (this.type === tt.ellipsis) { - spreadStart = this.start; - exprList.push(this.parseParenItem(this.parseRest())); - break; - } else { - if (this.type === tt.parenL && !innerParenStart) { - innerParenStart = this.start; - } - exprList.push(this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem)); - } - } - var innerEndPos = this.start, - innerEndLoc = this.startLoc; - this.expect(tt.parenR); +var _util = _dereq_("./util"); - if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) { - if (innerParenStart) this.unexpected(innerParenStart); - return this.parseParenArrowList(startPos, startLoc, exprList); - } +var pp = _state.Parser.prototype; - if (!exprList.length) this.unexpected(this.lastTokStart); - if (spreadStart) this.unexpected(spreadStart); - if (refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start); +// Convert existing expression atom to assignable pattern +// if possible. - if (exprList.length > 1) { - val = this.startNodeAt(innerStartPos, innerStartLoc); - val.expressions = exprList; - this.finishNodeAt(val, "SequenceExpression", innerEndPos, innerEndLoc); - } else { - val = exprList[0]; - } - } else { - val = this.parseParenExpression(); - } +pp.toAssignable = function (node, isBinding) { + if (this.options.ecmaVersion >= 6 && node) { + switch (node.type) { + case "Identifier": + case "ObjectPattern": + case "ArrayPattern": + case "AssignmentPattern": + break; - if (this.options.preserveParens) { - var par = this.startNodeAt(startPos, startLoc); - par.expression = val; - return this.finishNode(par, "ParenthesizedExpression"); - } else { - return val; - } -}; + case "ObjectExpression": + node.type = "ObjectPattern"; + for (var i = 0; i < node.properties.length; i++) { + var prop = node.properties[i]; + if (prop.kind !== "init") this.raise(prop.key.start, "Object pattern can't contain getter or setter"); + this.toAssignable(prop.value, isBinding); + } + break; -pp.parseParenItem = function (item) { - return item; -}; + case "ArrayExpression": + node.type = "ArrayPattern"; + this.toAssignableList(node.elements, isBinding); + break; -pp.parseParenArrowList = function (startPos, startLoc, exprList) { - return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList); -}; + case "AssignmentExpression": + if (node.operator === "=") { + node.type = "AssignmentPattern"; + delete node.operator; + } else { + this.raise(node.left.end, "Only '=' operator can be used for specifying default value."); + } + break; -// New's precedence is slightly tricky. It must allow its argument -// to be a `[]` or dot subscript expression, but not a call — at -// least, not without wrapping it in parentheses. Thus, it uses the + case "ParenthesizedExpression": + node.expression = this.toAssignable(node.expression, isBinding); + break; -var empty = []; + case "MemberExpression": + if (!isBinding) break; -pp.parseNew = function () { - var node = this.startNode(); - var meta = this.parseIdent(true); - if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) { - node.meta = meta; - node.property = this.parseIdent(true); - if (node.property.name !== "target") this.raise(node.property.start, "The only valid meta property for new is new.target"); - return this.finishNode(node, "MetaProperty"); + default: + this.raise(node.start, "Assigning to rvalue"); + } } - var startPos = this.start, - startLoc = this.startLoc; - node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true); - if (this.eat(tt.parenL)) node.arguments = this.parseExprList(tt.parenR, false);else node.arguments = empty; - return this.finishNode(node, "NewExpression"); + return node; }; -// Parse template expression. +// Convert list of expression atoms to binding list. -pp.parseTemplateElement = function () { - var elem = this.startNode(); - elem.value = { - raw: this.input.slice(this.start, this.end), - cooked: this.value - }; - this.next(); - elem.tail = this.type === tt.backQuote; - return this.finishNode(elem, "TemplateElement"); +pp.toAssignableList = function (exprList, isBinding) { + var end = exprList.length; + if (end) { + var last = exprList[end - 1]; + if (last && last.type == "RestElement") { + --end; + } else if (last && last.type == "SpreadElement") { + last.type = "RestElement"; + var arg = last.argument; + this.toAssignable(arg, isBinding); + if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern") this.unexpected(arg.start); + --end; + } + } + for (var i = 0; i < end; i++) { + var elt = exprList[i]; + if (elt) this.toAssignable(elt, isBinding); + } + return exprList; }; -pp.parseTemplate = function () { +// Parses spread element. + +pp.parseSpread = function (refShorthandDefaultPos) { var node = this.startNode(); this.next(); - node.expressions = []; - var curElt = this.parseTemplateElement(); - node.quasis = [curElt]; - while (!curElt.tail) { - this.expect(tt.dollarBraceL); - node.expressions.push(this.parseExpression()); - this.expect(tt.braceR); - node.quasis.push(curElt = this.parseTemplateElement()); - } + node.argument = this.parseMaybeAssign(refShorthandDefaultPos); + return this.finishNode(node, "SpreadElement"); +}; + +pp.parseRest = function () { + var node = this.startNode(); this.next(); - return this.finishNode(node, "TemplateLiteral"); + node.argument = this.type === _tokentype.types.name || this.type === _tokentype.types.bracketL ? this.parseBindingAtom() : this.unexpected(); + return this.finishNode(node, "RestElement"); }; -// Parse an object literal or binding pattern. +// Parses lvalue (assignable) atom. -pp.parseObj = function (isPattern, refShorthandDefaultPos) { - var node = this.startNode(), - first = true, - propHash = {}; - node.properties = []; - this.next(); - while (!this.eat(tt.braceR)) { - if (!first) { - this.expect(tt.comma); - if (this.afterTrailingComma(tt.braceR)) break; - } else first = false; +pp.parseBindingAtom = function () { + if (this.options.ecmaVersion < 6) return this.parseIdent(); + switch (this.type) { + case _tokentype.types.name: + return this.parseIdent(); - var prop = this.startNode(), - isGenerator = undefined, - startPos = undefined, - startLoc = undefined; - if (this.options.ecmaVersion >= 6) { - prop.method = false; - prop.shorthand = false; - if (isPattern || refShorthandDefaultPos) { - startPos = this.start; - startLoc = this.startLoc; - } - if (!isPattern) isGenerator = this.eat(tt.star); - } - this.parsePropertyName(prop); - this.parsePropertyValue(prop, isPattern, isGenerator, startPos, startLoc, refShorthandDefaultPos); - this.checkPropClash(prop, propHash); - node.properties.push(this.finishNode(prop, "Property")); - } - return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression"); -}; + case _tokentype.types.bracketL: + var node = this.startNode(); + this.next(); + node.elements = this.parseBindingList(_tokentype.types.bracketR, true, true); + return this.finishNode(node, "ArrayPattern"); -pp.parsePropertyValue = function (prop, isPattern, isGenerator, startPos, startLoc, refShorthandDefaultPos) { - if (this.eat(tt.colon)) { - prop.value = isPattern ? this.parseMaybeDefault(this.start, this.startLoc) : this.parseMaybeAssign(false, refShorthandDefaultPos); - prop.kind = "init"; - } else if (this.options.ecmaVersion >= 6 && this.type === tt.parenL) { - if (isPattern) this.unexpected(); - prop.kind = "init"; - prop.method = true; - prop.value = this.parseMethod(isGenerator); - } else if (this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" && (prop.key.name === "get" || prop.key.name === "set") && (this.type != tt.comma && this.type != tt.braceR)) { - if (isGenerator || isPattern) this.unexpected(); - prop.kind = prop.key.name; - this.parsePropertyName(prop); - prop.value = this.parseMethod(false); - } else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") { - prop.kind = "init"; - if (isPattern) { - if (this.isKeyword(prop.key.name) || this.strict && (reservedWords.strictBind(prop.key.name) || reservedWords.strict(prop.key.name)) || !this.options.allowReserved && this.isReservedWord(prop.key.name)) this.raise(prop.key.start, "Binding " + prop.key.name); - prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key); - } else if (this.type === tt.eq && refShorthandDefaultPos) { - if (!refShorthandDefaultPos.start) refShorthandDefaultPos.start = this.start; - prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key); - } else { - prop.value = prop.key; - } - prop.shorthand = true; - } else this.unexpected(); + case _tokentype.types.braceL: + return this.parseObj(true); + + default: + this.unexpected(); + } }; -pp.parsePropertyName = function (prop) { - if (this.options.ecmaVersion >= 6) { - if (this.eat(tt.bracketL)) { - prop.computed = true; - prop.key = this.parseMaybeAssign(); - this.expect(tt.bracketR); - return prop.key; +pp.parseBindingList = function (close, allowEmpty, allowTrailingComma) { + var elts = [], + first = true; + while (!this.eat(close)) { + if (first) first = false;else this.expect(_tokentype.types.comma); + if (allowEmpty && this.type === _tokentype.types.comma) { + elts.push(null); + } else if (allowTrailingComma && this.afterTrailingComma(close)) { + break; + } else if (this.type === _tokentype.types.ellipsis) { + var rest = this.parseRest(); + this.parseBindingListItem(rest); + elts.push(rest); + this.expect(close); + break; } else { - prop.computed = false; + var elem = this.parseMaybeDefault(this.start, this.startLoc); + this.parseBindingListItem(elem); + elts.push(elem); } } - return prop.key = this.type === tt.num || this.type === tt.string ? this.parseExprAtom() : this.parseIdent(true); + return elts; }; -// Initialize empty function node. - -pp.initFunction = function (node) { - node.id = null; - if (this.options.ecmaVersion >= 6) { - node.generator = false; - node.expression = false; - } +pp.parseBindingListItem = function (param) { + return param; }; -// Parse object or class method. +// Parses assignment pattern around given atom if possible. -pp.parseMethod = function (isGenerator) { - var node = this.startNode(); - this.initFunction(node); - this.expect(tt.parenL); - node.params = this.parseBindingList(tt.parenR, false, false); - var allowExpressionBody = undefined; - if (this.options.ecmaVersion >= 6) { - node.generator = isGenerator; - allowExpressionBody = true; - } else { - allowExpressionBody = false; - } - this.parseFunctionBody(node, allowExpressionBody); - return this.finishNode(node, "FunctionExpression"); +pp.parseMaybeDefault = function (startPos, startLoc, left) { + left = left || this.parseBindingAtom(); + if (!this.eat(_tokentype.types.eq)) return left; + var node = this.startNodeAt(startPos, startLoc); + node.operator = "="; + node.left = left; + node.right = this.parseMaybeAssign(); + return this.finishNode(node, "AssignmentPattern"); }; -// Parse arrow function expression with given parameters. +// Verify that a node is an lval — something that can be assigned +// to. -pp.parseArrowExpression = function (node, params) { - this.initFunction(node); - node.params = this.toAssignableList(params, true); - this.parseFunctionBody(node, true); - return this.finishNode(node, "ArrowFunctionExpression"); -}; - -// Parse function body and check parameters. - -pp.parseFunctionBody = function (node, allowExpression) { - var isExpression = allowExpression && this.type !== tt.braceL; - - if (isExpression) { - node.body = this.parseMaybeAssign(); - node.expression = true; - } else { - // Start a new scope with regard to labels and the `inFunction` - // flag (restore them to their old value afterwards). - var oldInFunc = this.inFunction, - oldInGen = this.inGenerator, - oldLabels = this.labels; - this.inFunction = true;this.inGenerator = node.generator;this.labels = []; - node.body = this.parseBlock(true); - node.expression = false; - this.inFunction = oldInFunc;this.inGenerator = oldInGen;this.labels = oldLabels; - } - - // If this is a strict mode function, verify that argument names - // are not repeated, and it does not try to bind the words `eval` - // or `arguments`. - if (this.strict || !isExpression && node.body.body.length && this.isUseStrict(node.body.body[0])) { - var nameHash = {}, - oldStrict = this.strict; - this.strict = true; - if (node.id) this.checkLVal(node.id, true); - for (var i = 0; i < node.params.length; i++) { - this.checkLVal(node.params[i], true, nameHash); - }this.strict = oldStrict; - } -}; +pp.checkLVal = function (expr, isBinding, checkClashes) { + switch (expr.type) { + case "Identifier": + if (this.strict && (_identifier.reservedWords.strictBind(expr.name) || _identifier.reservedWords.strict(expr.name))) this.raise(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode"); + if (checkClashes) { + if (_util.has(checkClashes, expr.name)) this.raise(expr.start, "Argument name clash in strict mode"); + checkClashes[expr.name] = true; + } + break; -// Parses a comma-separated list of expressions, and returns them as -// an array. `close` is the token type that ends the list, and -// `allowEmpty` can be turned on to allow subsequent commas with -// nothing in between them to be parsed as `null` (which is needed -// for array literals). + case "MemberExpression": + if (isBinding) this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression"); + break; -pp.parseExprList = function (close, allowTrailingComma, allowEmpty, refShorthandDefaultPos) { - var elts = [], - first = true; - while (!this.eat(close)) { - if (!first) { - this.expect(tt.comma); - if (allowTrailingComma && this.afterTrailingComma(close)) break; - } else first = false; + case "ObjectPattern": + for (var i = 0; i < expr.properties.length; i++) { + this.checkLVal(expr.properties[i].value, isBinding, checkClashes); + }break; - if (allowEmpty && this.type === tt.comma) { - elts.push(null); - } else { - if (this.type === tt.ellipsis) elts.push(this.parseSpread(refShorthandDefaultPos));else elts.push(this.parseMaybeAssign(false, refShorthandDefaultPos)); - } - } - return elts; -}; + case "ArrayPattern": + for (var i = 0; i < expr.elements.length; i++) { + var elem = expr.elements[i]; + if (elem) this.checkLVal(elem, isBinding, checkClashes); + } + break; -// Parse the next token as an identifier. If `liberal` is true (used -// when parsing properties), it will also convert keywords into -// identifiers. + case "AssignmentPattern": + this.checkLVal(expr.left, isBinding, checkClashes); + break; -pp.parseIdent = function (liberal) { - var node = this.startNode(); - if (liberal && this.options.allowReserved == "never") liberal = false; - if (this.type === tt.name) { - if (!liberal && (!this.options.allowReserved && this.isReservedWord(this.value) || this.strict && reservedWords.strict(this.value) && (this.options.ecmaVersion >= 6 || this.input.slice(this.start, this.end).indexOf("\\") == -1))) this.raise(this.start, "The keyword '" + this.value + "' is reserved"); - node.name = this.value; - } else if (liberal && this.type.keyword) { - node.name = this.type.keyword; - } else { - this.unexpected(); - } - this.next(); - return this.finishNode(node, "Identifier"); -}; + case "RestElement": + this.checkLVal(expr.argument, isBinding, checkClashes); + break; -// Parses yield expression inside generator. + case "ParenthesizedExpression": + this.checkLVal(expr.expression, isBinding, checkClashes); + break; -pp.parseYield = function () { - var node = this.startNode(); - this.next(); - if (this.type == tt.semi || this.canInsertSemicolon() || this.type != tt.star && !this.type.startsExpr) { - node.delegate = false; - node.argument = null; - } else { - node.delegate = this.eat(tt.star); - node.argument = this.parseMaybeAssign(); + default: + this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue"); } - return this.finishNode(node, "YieldExpression"); }; -// Parses array and generator comprehensions. +},{"./identifier":2,"./state":10,"./tokentype":14,"./util":15}],7:[function(_dereq_,module,exports){ +"use strict"; -pp.parseComprehension = function (node, isGenerator) { - node.blocks = []; - while (this.type === tt._for) { - var block = this.startNode(); - this.next(); - this.expect(tt.parenL); - block.left = this.parseBindingAtom(); - this.checkLVal(block.left, true); - this.expectContextual("of"); - block.right = this.parseExpression(); - this.expect(tt.parenR); - node.blocks.push(this.finishNode(block, "ComprehensionBlock")); - } - node.filter = this.eat(tt._if) ? this.parseParenExpression() : null; - node.body = this.parseExpression(); - this.expect(isGenerator ? tt.parenR : tt.bracketR); - node.generator = isGenerator; - return this.finishNode(node, "ComprehensionExpression"); -}; +exports.__esModule = true; -},{"./identifier":7,"./state":13,"./tokentype":17,"./util":18}],7:[function(_dereq_,module,exports){ +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +var _state = _dereq_("./state"); -// Test whether a given character code starts an identifier. +var _locutil = _dereq_("./locutil"); -"use strict"; +var Node = function Node(parser, pos, loc) { + _classCallCheck(this, Node); -exports.isIdentifierStart = isIdentifierStart; + this.type = ""; + this.start = pos; + this.end = 0; + if (parser.options.locations) this.loc = new _locutil.SourceLocation(parser, loc); + if (parser.options.directSourceFile) this.sourceFile = parser.options.directSourceFile; + if (parser.options.ranges) this.range = [pos, 0]; +}; -// Test whether a given character is part of an identifier. +exports.Node = Node; -exports.isIdentifierChar = isIdentifierChar; -exports.__esModule = true; -// This is a trick taken from Esprima. It turns out that, on -// non-Chrome browsers, to check whether a string is in a set, a -// predicate containing a big ugly `switch` statement is faster than -// a regular expression, and on Chrome the two are about on par. -// This function uses `eval` (non-lexical) to produce such a -// predicate from a space-separated string of words. -// -// It starts by sorting the words by length. +// Start an AST node, attaching a start offset. -function makePredicate(words) { - words = words.split(" "); - var f = "", - cats = []; - out: for (var i = 0; i < words.length; ++i) { - for (var j = 0; j < cats.length; ++j) { - if (cats[j][0].length == words[i].length) { - cats[j].push(words[i]); - continue out; - } - }cats.push([words[i]]); - } - function compareTo(arr) { - if (arr.length == 1) { - return f += "return str === " + JSON.stringify(arr[0]) + ";"; - }f += "switch(str){"; - for (var i = 0; i < arr.length; ++i) { - f += "case " + JSON.stringify(arr[i]) + ":"; - }f += "return true}return false;"; - } +var pp = _state.Parser.prototype; - // When there are more than three length categories, an outer - // switch first dispatches on the lengths, to save on comparisons. +pp.startNode = function () { + return new Node(this, this.start, this.startLoc); +}; - if (cats.length > 3) { - cats.sort(function (a, b) { - return b.length - a.length; - }); - f += "switch(str.length){"; - for (var i = 0; i < cats.length; ++i) { - var cat = cats[i]; - f += "case " + cat[0].length + ":"; - compareTo(cat); - } - f += "}" +pp.startNodeAt = function (pos, loc) { + return new Node(this, pos, loc); +}; - // Otherwise, simply generate a flat `switch` statement. +// Finish an AST node, adding `type` and `end` properties. - ; - } else { - compareTo(words); - } - return new Function("str", f); +function finishNodeAt(node, type, pos, loc) { + node.type = type; + node.end = pos; + if (this.options.locations) node.loc.end = loc; + if (this.options.ranges) node.range[1] = pos; + return node; } -// Reserved word lists for various dialects of the language - -var reservedWords = { - 3: makePredicate("abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile"), - 5: makePredicate("class enum extends super const export import"), - 6: makePredicate("enum await"), - strict: makePredicate("implements interface let package private protected public static yield"), - strictBind: makePredicate("eval arguments") +pp.finishNode = function (node, type) { + return finishNodeAt.call(this, node, type, this.lastTokEnd, this.lastTokEndLoc); }; -exports.reservedWords = reservedWords; -// And the keywords - -var ecma5AndLessKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this"; +// Finish node at given position -var keywords = { - 5: makePredicate(ecma5AndLessKeywords), - 6: makePredicate(ecma5AndLessKeywords + " let const class extends export import yield super") +pp.finishNodeAt = function (node, type, pos, loc) { + return finishNodeAt.call(this, node, type, pos, loc); }; -exports.keywords = keywords; -// ## Character categories - -// Big ugly regular expressions that match characters in the -// whitespace, identifier, and identifier-start categories. These -// are only applied when a character is found to actually have a -// code point above 128. -// Generated by `tools/generate-identifier-regex.js`. - -var nonASCIIidentifierStartChars = "ªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽͿΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠ-ࢲऄ-हऽॐक़-ॡॱ-ঀঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-హఽౘౙౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൠൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛮ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᧁ-ᧇᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕ℘-ℝℤΩℨK-ℹℼ-ℿⅅ-ⅉⅎⅠ-ↈⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞ々-〇〡-〩〱-〵〸-〼ぁ-ゖ゛-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚝꚠ-ꛯꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞭꞰꞱꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꩾ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭟꭤꭥꯀ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ"; -var nonASCIIidentifierChars = "‌‍·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-٩ٰۖ-ۜ۟-۪ۤۧۨ-ۭ۰-۹ܑܰ-݊ަ-ް߀-߉߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣤ-ःऺ-़ा-ॏ॑-ॗॢॣ०-९ঁ-ঃ়া-ৄেৈো-্ৗৢৣ০-৯ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑ੦-ੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣ૦-૯ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣ୦-୯ஂா-ூெ-ைொ-்ௗ௦-௯ఀ-ఃా-ౄె-ైొ-్ౕౖౢౣ౦-౯ಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣ೦-೯ഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣ൦-൯ංඃ්ා-ුූෘ-ෟ෦-෯ෲෳัิ-ฺ็-๎๐-๙ັິ-ູົຼ່-ໍ໐-໙༘༙༠-༩༹༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှ၀-၉ၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏ-ႝ፝-፟፩-፱ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝០-៩᠋-᠍᠐-᠙ᢩᤠ-ᤫᤰ-᤻᥆-᥏ᦰ-ᧀᧈᧉ᧐-᧚ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼-᪉᪐-᪙᪰-᪽ᬀ-ᬄ᬴-᭄᭐-᭙᭫-᭳ᮀ-ᮂᮡ-ᮭ᮰-᮹᯦-᯳ᰤ-᰷᱀-᱉᱐-᱙᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷼-᷿‿⁀⁔⃐-⃥⃜⃡-⃰⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꘠-꘩꙯ꙴ-꙽ꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-꣄꣐-꣙꣠-꣱꤀-꤉ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀꧐-꧙ꧥ꧰-꧹ꨩ-ꨶꩃꩌꩍ꩐-꩙ꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭꯰-꯹ﬞ︀-️︠-︭︳︴﹍-﹏0-9_"; +},{"./locutil":5,"./state":10}],8:[function(_dereq_,module,exports){ +"use strict"; -var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]"); -var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]"); +exports.__esModule = true; +exports.getOptions = getOptions; -nonASCIIidentifierStartChars = nonASCIIidentifierChars = null; +var _util = _dereq_("./util"); -// These are a run-length and offset encoded representation of the -// >0xffff code points that are a valid part of identifiers. The -// offset starts at 0x10000, and each pair of numbers represents an -// offset to the next range, and then a size of the range. They were -// generated by tools/generate-identifier-regex.js -var astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 17, 26, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 99, 39, 9, 51, 157, 310, 10, 21, 11, 7, 153, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 98, 21, 11, 25, 71, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 26, 45, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 955, 52, 76, 44, 33, 24, 27, 35, 42, 34, 4, 0, 13, 47, 15, 3, 22, 0, 38, 17, 2, 24, 133, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 32, 4, 287, 47, 21, 1, 2, 0, 185, 46, 82, 47, 21, 0, 60, 42, 502, 63, 32, 0, 449, 56, 1288, 920, 104, 110, 2962, 1070, 13266, 568, 8, 30, 114, 29, 19, 47, 17, 3, 32, 20, 6, 18, 881, 68, 12, 0, 67, 12, 16481, 1, 3071, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 4149, 196, 1340, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42710, 42, 4148, 12, 221, 16355, 541]; -var astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 1306, 2, 54, 14, 32, 9, 16, 3, 46, 10, 54, 9, 7, 2, 37, 13, 2, 9, 52, 0, 13, 2, 49, 13, 16, 9, 83, 11, 168, 11, 6, 9, 8, 2, 57, 0, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 316, 19, 13, 9, 214, 6, 3, 8, 112, 16, 16, 9, 82, 12, 9, 9, 535, 9, 20855, 9, 135, 4, 60, 6, 26, 9, 1016, 45, 17, 3, 19723, 1, 5319, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 4305, 6, 792618, 239]; +var _locutil = _dereq_("./locutil"); -// This has a complexity linear to the value of the code. The -// assumption is that looking up astral identifier characters is -// rare. -function isInAstralSet(code, set) { - var pos = 65536; - for (var i = 0; i < set.length; i += 2) { - pos += set[i]; - if (pos > code) { - return false; - }pos += set[i + 1]; - if (pos >= code) { - return true; - } - } -} -function isIdentifierStart(code, astral) { - if (code < 65) { - return code === 36; - }if (code < 91) { - return true; - }if (code < 97) { - return code === 95; - }if (code < 123) { - return true; - }if (code <= 65535) { - return code >= 170 && nonASCIIidentifierStart.test(String.fromCharCode(code)); - }if (astral === false) { - return false; - }return isInAstralSet(code, astralIdentifierStartCodes); -} +// A second optional argument can be given to further configure +// the parser process. These options are recognized: -function isIdentifierChar(code, astral) { - if (code < 48) { - return code === 36; - }if (code < 58) { - return true; - }if (code < 65) { - return false; - }if (code < 91) { - return true; - }if (code < 97) { - return code === 95; - }if (code < 123) { - return true; - }if (code <= 65535) { - return code >= 170 && nonASCIIidentifier.test(String.fromCharCode(code)); - }if (astral === false) { - return false; - }return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes); -} +var defaultOptions = { + // `ecmaVersion` indicates the ECMAScript version to parse. Must + // be either 3, or 5, or 6. This influences support for strict + // mode, the set of reserved words, support for getters and + // setters and other features. + ecmaVersion: 5, + // Source type ("script" or "module") for different semantics + sourceType: "script", + // `onInsertedSemicolon` can be a callback that will be called + // when a semicolon is automatically inserted. It will be passed + // th position of the comma as an offset, and if `locations` is + // enabled, it is given the location as a `{line, column}` object + // as second argument. + onInsertedSemicolon: null, + // `onTrailingComma` is similar to `onInsertedSemicolon`, but for + // trailing commas. + onTrailingComma: null, + // By default, reserved words are not enforced. Disable + // `allowReserved` to enforce them. When this option has the + // value "never", reserved words and keywords can also not be + // used as property names. + allowReserved: true, + // When enabled, a return at the top level is not considered an + // error. + allowReturnOutsideFunction: false, + // When enabled, import/export statements are not constrained to + // appearing at the top of the program. + allowImportExportEverywhere: false, + // When enabled, hashbang directive in the beginning of file + // is allowed and treated as a line comment. + allowHashBang: false, + // When `locations` is on, `loc` properties holding objects with + // `start` and `end` properties in `{line, column}` form (with + // line being 1-based and column 0-based) will be attached to the + // nodes. + locations: false, + // A function can be passed as `onToken` option, which will + // cause Acorn to call that function with object in the same + // format as tokenize() returns. Note that you are not + // allowed to call the parser from the callback—that will + // corrupt its internal state. + onToken: null, + // A function can be passed as `onComment` option, which will + // cause Acorn to call that function with `(block, text, start, + // end)` parameters whenever a comment is skipped. `block` is a + // boolean indicating whether this is a block (`/* */`) comment, + // `text` is the content of the comment, and `start` and `end` are + // character offsets that denote the start and end of the comment. + // When the `locations` option is on, two more parameters are + // passed, the full `{line, column}` locations of the start and + // end of the comments. Note that you are not allowed to call the + // parser from the callback—that will corrupt its internal state. + onComment: null, + // Nodes have their start and end characters offsets recorded in + // `start` and `end` properties (directly on the node, rather than + // the `loc` object, which holds line/column data. To also add a + // [semi-standardized][range] `range` property holding a `[start, + // end]` array with the same numbers, set the `ranges` option to + // `true`. + // + // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678 + ranges: false, + // It is possible to parse multiple files into a single AST by + // passing the tree produced by parsing the first file as + // `program` option in subsequent parses. This will add the + // toplevel forms of the parsed file to the `Program` (top) node + // of an existing parse tree. + program: null, + // When `locations` is on, you can pass this to record the source + // file in every node's `loc` object. + sourceFile: null, + // This value, if given, is stored in every node, whether + // `locations` is on or off. + directSourceFile: null, + // When enabled, parenthesized expressions are represented by + // (non-standard) ParenthesizedExpression nodes + preserveParens: false, + plugins: {} +}; + +exports.defaultOptions = defaultOptions; +// Interpret and default an options object + +function getOptions(opts) { + var options = {}; + for (var opt in defaultOptions) { + options[opt] = opts && _util.has(opts, opt) ? opts[opt] : defaultOptions[opt]; + }if (_util.isArray(options.onToken)) { + (function () { + var tokens = options.onToken; + options.onToken = function (token) { + return tokens.push(token); + }; + })(); + } + if (_util.isArray(options.onComment)) options.onComment = pushComment(options, options.onComment); + + return options; +} + +function pushComment(options, array) { + return function (block, text, start, end, startLoc, endLoc) { + var comment = { + type: block ? "Block" : "Line", + value: text, + start: start, + end: end + }; + if (options.locations) comment.loc = new _locutil.SourceLocation(this, startLoc, endLoc); + if (options.ranges) comment.range = [start, end]; + array.push(comment); + }; +} -},{}],8:[function(_dereq_,module,exports){ +},{"./locutil":5,"./util":15}],9:[function(_dereq_,module,exports){ "use strict"; -var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; +var _tokentype = _dereq_("./tokentype"); -// The `getLineInfo` function is mostly useful when the -// `locations` option is off (for performance reasons) and you -// want to find the line/column position for a given character -// offset. `input` should be the code string that the offset refers -// into. +var _state = _dereq_("./state"); -exports.getLineInfo = getLineInfo; -exports.__esModule = true; +var _whitespace = _dereq_("./whitespace"); -var Parser = _dereq_("./state").Parser; +var pp = _state.Parser.prototype; -var lineBreakG = _dereq_("./whitespace").lineBreakG; +// ## Parser utilities -var deprecate = _dereq_("util").deprecate; +// Test whether a statement node is the string literal `"use strict"`. -// These are used when `options.locations` is on, for the -// `startLoc` and `endLoc` properties. +pp.isUseStrict = function (stmt) { + return this.options.ecmaVersion >= 5 && stmt.type === "ExpressionStatement" && stmt.expression.type === "Literal" && stmt.expression.raw.slice(1, -1) === "use strict"; +}; -var Position = exports.Position = (function () { - function Position(line, col) { - _classCallCheck(this, Position); +// Predicate that tests whether the next token is of the given +// type, and if yes, consumes it as a side effect. - this.line = line; - this.column = col; +pp.eat = function (type) { + if (this.type === type) { + this.next(); + return true; + } else { + return false; } +}; - Position.prototype.offset = function offset(n) { - return new Position(this.line, this.column + n); - }; +// Tests whether parsed token is a contextual keyword. - return Position; -})(); +pp.isContextual = function (name) { + return this.type === _tokentype.types.name && this.value === name; +}; -var SourceLocation = exports.SourceLocation = function SourceLocation(p, start, end) { - _classCallCheck(this, SourceLocation); +// Consumes contextual keyword if possible. - this.start = start; - this.end = end; - if (p.sourceFile !== null) this.source = p.sourceFile; +pp.eatContextual = function (name) { + return this.value === name && this.eat(_tokentype.types.name); }; -function getLineInfo(input, offset) { - for (var line = 1, cur = 0;;) { - lineBreakG.lastIndex = cur; - var match = lineBreakG.exec(input); - if (match && match.index < offset) { - ++line; - cur = match.index + match[0].length; - } else { - return new Position(line, offset - cur); - } +// Asserts that following token is given contextual keyword. + +pp.expectContextual = function (name) { + if (!this.eatContextual(name)) this.unexpected(); +}; + +// Test whether a semicolon can be inserted at the current position. + +pp.canInsertSemicolon = function () { + return this.type === _tokentype.types.eof || this.type === _tokentype.types.braceR || _whitespace.lineBreak.test(this.input.slice(this.lastTokEnd, this.start)); +}; + +pp.insertSemicolon = function () { + if (this.canInsertSemicolon()) { + if (this.options.onInsertedSemicolon) this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc); + return true; } -} +}; -var pp = Parser.prototype; +// Consume a semicolon, or, failing that, see if we are allowed to +// pretend that there is a semicolon at this position. -// This function is used to raise exceptions on parse errors. It -// takes an offset integer (into the current `input`) to indicate -// the location of the error, attaches the position to the end -// of the error message, and then raises a `SyntaxError` with that -// message. +pp.semicolon = function () { + if (!this.eat(_tokentype.types.semi) && !this.insertSemicolon()) this.unexpected(); +}; -pp.raise = function (pos, message) { - var loc = getLineInfo(this.input, pos); - message += " (" + loc.line + ":" + loc.column + ")"; - var err = new SyntaxError(message); - err.pos = pos;err.loc = loc;err.raisedAt = this.pos; - throw err; +pp.afterTrailingComma = function (tokType) { + if (this.type == tokType) { + if (this.options.onTrailingComma) this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc); + this.next(); + return true; + } }; -pp.curPosition = function () { - return new Position(this.curLine, this.pos - this.lineStart); +// Expect a token of a given type. If found, consume it, otherwise, +// raise an unexpected token error. + +pp.expect = function (type) { + this.eat(type) || this.unexpected(); }; -pp.markPosition = function () { - return this.options.locations ? [this.start, this.startLoc] : this.start; +// Raise an unexpected token error. + +pp.unexpected = function (pos) { + this.raise(pos != null ? pos : this.start, "Unexpected token"); }; -},{"./state":13,"./whitespace":19,"util":5}],9:[function(_dereq_,module,exports){ +},{"./state":10,"./tokentype":14,"./whitespace":16}],10:[function(_dereq_,module,exports){ "use strict"; -var tt = _dereq_("./tokentype").types; +exports.__esModule = true; -var Parser = _dereq_("./state").Parser; +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -var reservedWords = _dereq_("./identifier").reservedWords; +var _identifier = _dereq_("./identifier"); -var has = _dereq_("./util").has; +var _tokentype = _dereq_("./tokentype"); -var pp = Parser.prototype; +var _whitespace = _dereq_("./whitespace"); -// Convert existing expression atom to assignable pattern -// if possible. +var _options = _dereq_("./options"); -pp.toAssignable = function (node, isBinding) { - if (this.options.ecmaVersion >= 6 && node) { - switch (node.type) { - case "Identifier": - case "ObjectPattern": - case "ArrayPattern": - case "AssignmentPattern": - break; +// Registered plugins +var plugins = {}; - case "ObjectExpression": - node.type = "ObjectPattern"; - for (var i = 0; i < node.properties.length; i++) { - var prop = node.properties[i]; - if (prop.kind !== "init") this.raise(prop.key.start, "Object pattern can't contain getter or setter"); - this.toAssignable(prop.value, isBinding); - } - break; +exports.plugins = plugins; - case "ArrayExpression": - node.type = "ArrayPattern"; - this.toAssignableList(node.elements, isBinding); - break; +var Parser = (function () { + function Parser(options, input, startPos) { + _classCallCheck(this, Parser); - case "AssignmentExpression": - if (node.operator === "=") { - node.type = "AssignmentPattern"; - } else { - this.raise(node.left.end, "Only '=' operator can be used for specifying default value."); - } - break; + this.options = _options.getOptions(options); + this.sourceFile = this.options.sourceFile; + this.isKeyword = _identifier.keywords[this.options.ecmaVersion >= 6 ? 6 : 5]; + this.isReservedWord = _identifier.reservedWords[this.options.ecmaVersion]; + this.input = String(input); - case "ParenthesizedExpression": - node.expression = this.toAssignable(node.expression, isBinding); - break; + // Load plugins + this.loadPlugins(this.options.plugins); - case "MemberExpression": - if (!isBinding) break; + // Set up token state - default: - this.raise(node.start, "Assigning to rvalue"); + // The current position of the tokenizer in the input. + if (startPos) { + this.pos = startPos; + this.lineStart = Math.max(0, this.input.lastIndexOf("\n", startPos)); + this.curLine = this.input.slice(0, this.lineStart).split(_whitespace.lineBreak).length; + } else { + this.pos = this.lineStart = 0; + this.curLine = 1; } - } - return node; -}; -// Convert list of expression atoms to binding list. + // Properties of the current token: + // Its type + this.type = _tokentype.types.eof; + // For tokens that include more information than their type, the value + this.value = null; + // Its start and end offset + this.start = this.end = this.pos; + // And, if locations are used, the {line, column} object + // corresponding to those offsets + this.startLoc = this.endLoc = this.curPosition(); + + // Position information for the previous token + this.lastTokEndLoc = this.lastTokStartLoc = null; + this.lastTokStart = this.lastTokEnd = this.pos; + + // The context stack is used to superficially track syntactic + // context to predict whether a regular expression is allowed in a + // given position. + this.context = this.initialContext(); + this.exprAllowed = true; -pp.toAssignableList = function (exprList, isBinding) { - var end = exprList.length; - if (end) { - var last = exprList[end - 1]; - if (last && last.type == "RestElement") { - --end; - } else if (last && last.type == "SpreadElement") { - last.type = "RestElement"; - var arg = last.argument; - this.toAssignable(arg, isBinding); - if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern") this.unexpected(arg.start); - --end; - } - } - for (var i = 0; i < end; i++) { - var elt = exprList[i]; - if (elt) this.toAssignable(elt, isBinding); - } - return exprList; -}; - -// Parses spread element. - -pp.parseSpread = function (refShorthandDefaultPos) { - var node = this.startNode(); - this.next(); - node.argument = this.parseMaybeAssign(refShorthandDefaultPos); - return this.finishNode(node, "SpreadElement"); -}; - -pp.parseRest = function () { - var node = this.startNode(); - this.next(); - node.argument = this.type === tt.name || this.type === tt.bracketL ? this.parseBindingAtom() : this.unexpected(); - return this.finishNode(node, "RestElement"); -}; - -// Parses lvalue (assignable) atom. - -pp.parseBindingAtom = function () { - if (this.options.ecmaVersion < 6) return this.parseIdent(); - switch (this.type) { - case tt.name: - return this.parseIdent(); + // Figure out if it's a module code. + this.strict = this.inModule = this.options.sourceType === "module"; - case tt.bracketL: - var node = this.startNode(); - this.next(); - node.elements = this.parseBindingList(tt.bracketR, true, true); - return this.finishNode(node, "ArrayPattern"); + // Used to signify the start of a potential arrow function + this.potentialArrowAt = -1; - case tt.braceL: - return this.parseObj(true); + // Flags to track whether we are in a function, a generator. + this.inFunction = this.inGenerator = false; + // Labels in scope. + this.labels = []; - default: - this.unexpected(); + // If enabled, skip leading hashbang line. + if (this.pos === 0 && this.options.allowHashBang && this.input.slice(0, 2) === "#!") this.skipLineComment(2); } -}; -pp.parseBindingList = function (close, allowEmpty, allowTrailingComma) { - var elts = [], - first = true; - while (!this.eat(close)) { - if (first) first = false;else this.expect(tt.comma); - if (allowEmpty && this.type === tt.comma) { - elts.push(null); - } else if (allowTrailingComma && this.afterTrailingComma(close)) { - break; - } else if (this.type === tt.ellipsis) { - var rest = this.parseRest(); - this.parseBindingListItem(rest); - elts.push(rest); - this.expect(close); - break; - } else { - var elem = this.parseMaybeDefault(this.start, this.startLoc); - this.parseBindingListItem(elem); - elts.push(elem); - } - } - return elts; -}; + Parser.prototype.extend = function extend(name, f) { + this[name] = f(this[name]); + }; -pp.parseBindingListItem = function (param) { - return param; -}; + Parser.prototype.loadPlugins = function loadPlugins(pluginConfigs) { + for (var _name in pluginConfigs) { + var plugin = plugins[_name]; + if (!plugin) throw new Error("Plugin '" + _name + "' not found"); + plugin(this, pluginConfigs[_name]); + } + }; -// Parses assignment pattern around given atom if possible. + Parser.prototype.parse = function parse() { + var node = this.options.program || this.startNode(); + this.nextToken(); + return this.parseTopLevel(node); + }; -pp.parseMaybeDefault = function (startPos, startLoc, left) { - if (Array.isArray(startPos)) { - if (this.options.locations && noCalls === undefined) { - // shift arguments to left by one - left = startLoc; - // flatten startPos - startLoc = startPos[1]; - startPos = startPos[0]; - } - } - left = left || this.parseBindingAtom(); - if (!this.eat(tt.eq)) return left; - var node = this.startNodeAt(startPos, startLoc); - node.operator = "="; - node.left = left; - node.right = this.parseMaybeAssign(); - return this.finishNode(node, "AssignmentPattern"); -}; + return Parser; +})(); -// Verify that a node is an lval — something that can be assigned -// to. +exports.Parser = Parser; -pp.checkLVal = function (expr, isBinding, checkClashes) { - switch (expr.type) { - case "Identifier": - if (this.strict && (reservedWords.strictBind(expr.name) || reservedWords.strict(expr.name))) this.raise(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode"); - if (checkClashes) { - if (has(checkClashes, expr.name)) this.raise(expr.start, "Argument name clash in strict mode"); - checkClashes[expr.name] = true; - } - break; +},{"./identifier":2,"./options":8,"./tokentype":14,"./whitespace":16}],11:[function(_dereq_,module,exports){ +"use strict"; - case "MemberExpression": - if (isBinding) this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression"); - break; +var _tokentype = _dereq_("./tokentype"); - case "ObjectPattern": - for (var i = 0; i < expr.properties.length; i++) { - this.checkLVal(expr.properties[i].value, isBinding, checkClashes); - }break; +var _state = _dereq_("./state"); - case "ArrayPattern": - for (var i = 0; i < expr.elements.length; i++) { - var elem = expr.elements[i]; - if (elem) this.checkLVal(elem, isBinding, checkClashes); - } - break; +var _whitespace = _dereq_("./whitespace"); - case "AssignmentPattern": - this.checkLVal(expr.left, isBinding, checkClashes); - break; +var pp = _state.Parser.prototype; - case "RestElement": - this.checkLVal(expr.argument, isBinding, checkClashes); - break; +// ### Statement parsing - case "ParenthesizedExpression": - this.checkLVal(expr.expression, isBinding, checkClashes); - break; +// Parse a program. Initializes the parser, reads any number of +// statements, and wraps them in a Program node. Optionally takes a +// `program` argument. If present, the statements will be appended +// to its body instead of creating a new node. - default: - this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue"); +pp.parseTopLevel = function (node) { + var first = true; + if (!node.body) node.body = []; + while (this.type !== _tokentype.types.eof) { + var stmt = this.parseStatement(true, true); + node.body.push(stmt); + if (first) { + if (this.isUseStrict(stmt)) this.setStrict(true); + first = false; + } + } + this.next(); + if (this.options.ecmaVersion >= 6) { + node.sourceType = this.options.sourceType; } + return this.finishNode(node, "Program"); }; -},{"./identifier":7,"./state":13,"./tokentype":17,"./util":18}],10:[function(_dereq_,module,exports){ -"use strict"; - -var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; - -exports.__esModule = true; +var loopLabel = { kind: "loop" }, + switchLabel = { kind: "switch" }; -var Parser = _dereq_("./state").Parser; +// Parse a single statement. +// +// If expecting a statement and finding a slash operator, parse a +// regular expression literal. This is to handle cases like +// `if (foo) /blah/.exec(foo)`, where looking at the previous token +// does not help. -var SourceLocation = _dereq_("./location").SourceLocation; +pp.parseStatement = function (declaration, topLevel) { + var starttype = this.type, + node = this.startNode(); -// Start an AST node, attaching a start offset. + // Most types of statements are recognized by the keyword they + // start with. Many are trivial to parse, some require a bit of + // complexity. -var pp = Parser.prototype; + switch (starttype) { + case _tokentype.types._break:case _tokentype.types._continue: + return this.parseBreakContinueStatement(node, starttype.keyword); + case _tokentype.types._debugger: + return this.parseDebuggerStatement(node); + case _tokentype.types._do: + return this.parseDoStatement(node); + case _tokentype.types._for: + return this.parseForStatement(node); + case _tokentype.types._function: + if (!declaration && this.options.ecmaVersion >= 6) this.unexpected(); + return this.parseFunctionStatement(node); + case _tokentype.types._class: + if (!declaration) this.unexpected(); + return this.parseClass(node, true); + case _tokentype.types._if: + return this.parseIfStatement(node); + case _tokentype.types._return: + return this.parseReturnStatement(node); + case _tokentype.types._switch: + return this.parseSwitchStatement(node); + case _tokentype.types._throw: + return this.parseThrowStatement(node); + case _tokentype.types._try: + return this.parseTryStatement(node); + case _tokentype.types._let:case _tokentype.types._const: + if (!declaration) this.unexpected(); // NOTE: falls through to _var + case _tokentype.types._var: + return this.parseVarStatement(node, starttype); + case _tokentype.types._while: + return this.parseWhileStatement(node); + case _tokentype.types._with: + return this.parseWithStatement(node); + case _tokentype.types.braceL: + return this.parseBlock(); + case _tokentype.types.semi: + return this.parseEmptyStatement(node); + case _tokentype.types._export: + case _tokentype.types._import: + if (!this.options.allowImportExportEverywhere) { + if (!topLevel) this.raise(this.start, "'import' and 'export' may only appear at the top level"); + if (!this.inModule) this.raise(this.start, "'import' and 'export' may appear only with 'sourceType: module'"); + } + return starttype === _tokentype.types._import ? this.parseImport(node) : this.parseExport(node); -var Node = exports.Node = function Node() { - _classCallCheck(this, Node); + // If the statement does not start with a statement keyword or a + // brace, it's an ExpressionStatement or LabeledStatement. We + // simply start parsing an expression, and afterwards, if the + // next token is a colon and the expression was a simple + // Identifier node, we switch to interpreting it as a label. + default: + var maybeName = this.value, + expr = this.parseExpression(); + if (starttype === _tokentype.types.name && expr.type === "Identifier" && this.eat(_tokentype.types.colon)) return this.parseLabeledStatement(node, maybeName, expr);else return this.parseExpressionStatement(node, expr); + } }; -pp.startNode = function () { - var node = new Node(); - node.start = this.start; - if (this.options.locations) node.loc = new SourceLocation(this, this.startLoc); - if (this.options.directSourceFile) node.sourceFile = this.options.directSourceFile; - if (this.options.ranges) node.range = [this.start, 0]; - return node; -}; +pp.parseBreakContinueStatement = function (node, keyword) { + var isBreak = keyword == "break"; + this.next(); + if (this.eat(_tokentype.types.semi) || this.insertSemicolon()) node.label = null;else if (this.type !== _tokentype.types.name) this.unexpected();else { + node.label = this.parseIdent(); + this.semicolon(); + } -pp.startNodeAt = function (pos, loc) { - var node = new Node(); - if (Array.isArray(pos)) { - if (this.options.locations && loc === undefined) { - // flatten pos - loc = pos[1]; - pos = pos[0]; + // Verify that there is an actual destination to break or + // continue to. + for (var i = 0; i < this.labels.length; ++i) { + var lab = this.labels[i]; + if (node.label == null || lab.name === node.label.name) { + if (lab.kind != null && (isBreak || lab.kind === "loop")) break; + if (node.label && isBreak) break; } } - node.start = pos; - if (this.options.locations) node.loc = new SourceLocation(this, loc); - if (this.options.directSourceFile) node.sourceFile = this.options.directSourceFile; - if (this.options.ranges) node.range = [pos, 0]; - return node; + if (i === this.labels.length) this.raise(node.start, "Unsyntactic " + keyword); + return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement"); }; -// Finish an AST node, adding `type` and `end` properties. - -pp.finishNode = function (node, type) { - node.type = type; - node.end = this.lastTokEnd; - if (this.options.locations) node.loc.end = this.lastTokEndLoc; - if (this.options.ranges) node.range[1] = this.lastTokEnd; - return node; +pp.parseDebuggerStatement = function (node) { + this.next(); + this.semicolon(); + return this.finishNode(node, "DebuggerStatement"); }; -// Finish node at given position - -pp.finishNodeAt = function (node, type, pos, loc) { - node.type = type; - if (Array.isArray(pos)) { - if (this.options.locations && loc === undefined) { - // flatten pos - loc = pos[1]; - pos = pos[0]; - } - } - node.end = pos; - if (this.options.locations) node.loc.end = loc; - if (this.options.ranges) node.range[1] = pos; - return node; +pp.parseDoStatement = function (node) { + this.next(); + this.labels.push(loopLabel); + node.body = this.parseStatement(false); + this.labels.pop(); + this.expect(_tokentype.types._while); + node.test = this.parseParenExpression(); + if (this.options.ecmaVersion >= 6) this.eat(_tokentype.types.semi);else this.semicolon(); + return this.finishNode(node, "DoWhileStatement"); }; -},{"./location":8,"./state":13}],11:[function(_dereq_,module,exports){ - - -// Interpret and default an options object - -"use strict"; - -exports.getOptions = getOptions; -exports.__esModule = true; +// Disambiguating between a `for` and a `for`/`in` or `for`/`of` +// loop is non-trivial. Basically, we have to parse the init `var` +// statement or expression, disallowing the `in` operator (see +// the second parameter to `parseExpression`), and then check +// whether the next token is `in` or `of`. When there is no init +// part (semicolon immediately after the opening parenthesis), it +// is a regular `for` loop. -var _util = _dereq_("./util"); +pp.parseForStatement = function (node) { + this.next(); + this.labels.push(loopLabel); + this.expect(_tokentype.types.parenL); + if (this.type === _tokentype.types.semi) return this.parseFor(node, null); + if (this.type === _tokentype.types._var || this.type === _tokentype.types._let || this.type === _tokentype.types._const) { + var _init = this.startNode(), + varKind = this.type; + this.next(); + this.parseVar(_init, true, varKind); + this.finishNode(_init, "VariableDeclaration"); + if ((this.type === _tokentype.types._in || this.options.ecmaVersion >= 6 && this.isContextual("of")) && _init.declarations.length === 1 && !(varKind !== _tokentype.types._var && _init.declarations[0].init)) return this.parseForIn(node, _init); + return this.parseFor(node, _init); + } + var refShorthandDefaultPos = { start: 0 }; + var init = this.parseExpression(true, refShorthandDefaultPos); + if (this.type === _tokentype.types._in || this.options.ecmaVersion >= 6 && this.isContextual("of")) { + this.toAssignable(init); + this.checkLVal(init); + return this.parseForIn(node, init); + } else if (refShorthandDefaultPos.start) { + this.unexpected(refShorthandDefaultPos.start); + } + return this.parseFor(node, init); +}; + +pp.parseFunctionStatement = function (node) { + this.next(); + return this.parseFunction(node, true); +}; + +pp.parseIfStatement = function (node) { + this.next(); + node.test = this.parseParenExpression(); + node.consequent = this.parseStatement(false); + node.alternate = this.eat(_tokentype.types._else) ? this.parseStatement(false) : null; + return this.finishNode(node, "IfStatement"); +}; + +pp.parseReturnStatement = function (node) { + if (!this.inFunction && !this.options.allowReturnOutsideFunction) this.raise(this.start, "'return' outside of function"); + this.next(); + + // In `return` (and `break`/`continue`), the keywords with + // optional arguments, we eagerly look for a semicolon or the + // possibility to insert one. + + if (this.eat(_tokentype.types.semi) || this.insertSemicolon()) node.argument = null;else { + node.argument = this.parseExpression();this.semicolon(); + } + return this.finishNode(node, "ReturnStatement"); +}; + +pp.parseSwitchStatement = function (node) { + this.next(); + node.discriminant = this.parseParenExpression(); + node.cases = []; + this.expect(_tokentype.types.braceL); + this.labels.push(switchLabel); + + // Statements under must be grouped (by label) in SwitchCase + // nodes. `cur` is used to keep the node that we are currently + // adding statements to. + + for (var cur, sawDefault = false; this.type != _tokentype.types.braceR;) { + if (this.type === _tokentype.types._case || this.type === _tokentype.types._default) { + var isCase = this.type === _tokentype.types._case; + if (cur) this.finishNode(cur, "SwitchCase"); + node.cases.push(cur = this.startNode()); + cur.consequent = []; + this.next(); + if (isCase) { + cur.test = this.parseExpression(); + } else { + if (sawDefault) this.raise(this.lastTokStart, "Multiple default clauses"); + sawDefault = true; + cur.test = null; + } + this.expect(_tokentype.types.colon); + } else { + if (!cur) this.unexpected(); + cur.consequent.push(this.parseStatement(true)); + } + } + if (cur) this.finishNode(cur, "SwitchCase"); + this.next(); // Closing brace + this.labels.pop(); + return this.finishNode(node, "SwitchStatement"); +}; + +pp.parseThrowStatement = function (node) { + this.next(); + if (_whitespace.lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) this.raise(this.lastTokEnd, "Illegal newline after throw"); + node.argument = this.parseExpression(); + this.semicolon(); + return this.finishNode(node, "ThrowStatement"); +}; + +// Reused empty array added for node fields that are always empty. + +var empty = []; + +pp.parseTryStatement = function (node) { + this.next(); + node.block = this.parseBlock(); + node.handler = null; + if (this.type === _tokentype.types._catch) { + var clause = this.startNode(); + this.next(); + this.expect(_tokentype.types.parenL); + clause.param = this.parseBindingAtom(); + this.checkLVal(clause.param, true); + this.expect(_tokentype.types.parenR); + clause.guard = null; + clause.body = this.parseBlock(); + node.handler = this.finishNode(clause, "CatchClause"); + } + node.guardedHandlers = empty; + node.finalizer = this.eat(_tokentype.types._finally) ? this.parseBlock() : null; + if (!node.handler && !node.finalizer) this.raise(node.start, "Missing catch or finally clause"); + return this.finishNode(node, "TryStatement"); +}; + +pp.parseVarStatement = function (node, kind) { + this.next(); + this.parseVar(node, false, kind); + this.semicolon(); + return this.finishNode(node, "VariableDeclaration"); +}; + +pp.parseWhileStatement = function (node) { + this.next(); + node.test = this.parseParenExpression(); + this.labels.push(loopLabel); + node.body = this.parseStatement(false); + this.labels.pop(); + return this.finishNode(node, "WhileStatement"); +}; + +pp.parseWithStatement = function (node) { + if (this.strict) this.raise(this.start, "'with' in strict mode"); + this.next(); + node.object = this.parseParenExpression(); + node.body = this.parseStatement(false); + return this.finishNode(node, "WithStatement"); +}; + +pp.parseEmptyStatement = function (node) { + this.next(); + return this.finishNode(node, "EmptyStatement"); +}; + +pp.parseLabeledStatement = function (node, maybeName, expr) { + for (var i = 0; i < this.labels.length; ++i) { + if (this.labels[i].name === maybeName) this.raise(expr.start, "Label '" + maybeName + "' is already declared"); + }var kind = this.type.isLoop ? "loop" : this.type === _tokentype.types._switch ? "switch" : null; + for (var i = this.labels.length - 1; i >= 0; i--) { + var label = this.labels[i]; + if (label.statementStart == node.start) { + label.statementStart = this.start; + label.kind = kind; + } else break; + } + this.labels.push({ name: maybeName, kind: kind, statementStart: this.start }); + node.body = this.parseStatement(true); + this.labels.pop(); + node.label = expr; + return this.finishNode(node, "LabeledStatement"); +}; + +pp.parseExpressionStatement = function (node, expr) { + node.expression = expr; + this.semicolon(); + return this.finishNode(node, "ExpressionStatement"); +}; + +// Parse a semicolon-enclosed block of statements, handling `"use +// strict"` declarations when `allowStrict` is true (used for +// function bodies). + +pp.parseBlock = function (allowStrict) { + var node = this.startNode(), + first = true, + oldStrict = undefined; + node.body = []; + this.expect(_tokentype.types.braceL); + while (!this.eat(_tokentype.types.braceR)) { + var stmt = this.parseStatement(true); + node.body.push(stmt); + if (first && allowStrict && this.isUseStrict(stmt)) { + oldStrict = this.strict; + this.setStrict(this.strict = true); + } + first = false; + } + if (oldStrict === false) this.setStrict(false); + return this.finishNode(node, "BlockStatement"); +}; + +// Parse a regular `for` loop. The disambiguation code in +// `parseStatement` will already have parsed the init statement or +// expression. + +pp.parseFor = function (node, init) { + node.init = init; + this.expect(_tokentype.types.semi); + node.test = this.type === _tokentype.types.semi ? null : this.parseExpression(); + this.expect(_tokentype.types.semi); + node.update = this.type === _tokentype.types.parenR ? null : this.parseExpression(); + this.expect(_tokentype.types.parenR); + node.body = this.parseStatement(false); + this.labels.pop(); + return this.finishNode(node, "ForStatement"); +}; + +// Parse a `for`/`in` and `for`/`of` loop, which are almost +// same from parser's perspective. + +pp.parseForIn = function (node, init) { + var type = this.type === _tokentype.types._in ? "ForInStatement" : "ForOfStatement"; + this.next(); + node.left = init; + node.right = this.parseExpression(); + this.expect(_tokentype.types.parenR); + node.body = this.parseStatement(false); + this.labels.pop(); + return this.finishNode(node, type); +}; + +// Parse a list of variable declarations. + +pp.parseVar = function (node, isFor, kind) { + node.declarations = []; + node.kind = kind.keyword; + for (;;) { + var decl = this.startNode(); + this.parseVarId(decl); + if (this.eat(_tokentype.types.eq)) { + decl.init = this.parseMaybeAssign(isFor); + } else if (kind === _tokentype.types._const && !(this.type === _tokentype.types._in || this.options.ecmaVersion >= 6 && this.isContextual("of"))) { + this.unexpected(); + } else if (decl.id.type != "Identifier" && !(isFor && (this.type === _tokentype.types._in || this.isContextual("of")))) { + this.raise(this.lastTokEnd, "Complex binding patterns require an initialization value"); + } else { + decl.init = null; + } + node.declarations.push(this.finishNode(decl, "VariableDeclarator")); + if (!this.eat(_tokentype.types.comma)) break; + } + return node; +}; + +pp.parseVarId = function (decl) { + decl.id = this.parseBindingAtom(); + this.checkLVal(decl.id, true); +}; + +// Parse a function declaration or literal (depending on the +// `isStatement` parameter). + +pp.parseFunction = function (node, isStatement, allowExpressionBody) { + this.initFunction(node); + if (this.options.ecmaVersion >= 6) node.generator = this.eat(_tokentype.types.star); + if (isStatement || this.type === _tokentype.types.name) node.id = this.parseIdent(); + this.parseFunctionParams(node); + this.parseFunctionBody(node, allowExpressionBody); + return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression"); +}; + +pp.parseFunctionParams = function (node) { + this.expect(_tokentype.types.parenL); + node.params = this.parseBindingList(_tokentype.types.parenR, false, false); +}; + +// Parse a class declaration or literal (depending on the +// `isStatement` parameter). + +pp.parseClass = function (node, isStatement) { + this.next(); + this.parseClassId(node, isStatement); + this.parseClassSuper(node); + var classBody = this.startNode(); + var hadConstructor = false; + classBody.body = []; + this.expect(_tokentype.types.braceL); + while (!this.eat(_tokentype.types.braceR)) { + if (this.eat(_tokentype.types.semi)) continue; + var method = this.startNode(); + var isGenerator = this.eat(_tokentype.types.star); + var isMaybeStatic = this.type === _tokentype.types.name && this.value === "static"; + this.parsePropertyName(method); + method["static"] = isMaybeStatic && this.type !== _tokentype.types.parenL; + if (method["static"]) { + if (isGenerator) this.unexpected(); + isGenerator = this.eat(_tokentype.types.star); + this.parsePropertyName(method); + } + method.kind = "method"; + var isGetSet = false; + if (!method.computed) { + var key = method.key; + + if (!isGenerator && key.type === "Identifier" && this.type !== _tokentype.types.parenL && (key.name === "get" || key.name === "set")) { + isGetSet = true; + method.kind = key.name; + key = this.parsePropertyName(method); + } + if (!method["static"] && (key.type === "Identifier" && key.name === "constructor" || key.type === "Literal" && key.value === "constructor")) { + if (hadConstructor) this.raise(key.start, "Duplicate constructor in the same class"); + if (isGetSet) this.raise(key.start, "Constructor can't have get/set modifier"); + if (isGenerator) this.raise(key.start, "Constructor can't be a generator"); + method.kind = "constructor"; + hadConstructor = true; + } + } + this.parseClassMethod(classBody, method, isGenerator); + if (isGetSet) { + var paramCount = method.kind === "get" ? 0 : 1; + if (method.value.params.length !== paramCount) { + var start = method.value.start; + if (method.kind === "get") this.raise(start, "getter should have no params");else this.raise(start, "setter should have exactly one param"); + } + } + } + node.body = this.finishNode(classBody, "ClassBody"); + return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression"); +}; + +pp.parseClassMethod = function (classBody, method, isGenerator) { + method.value = this.parseMethod(isGenerator); + classBody.body.push(this.finishNode(method, "MethodDefinition")); +}; + +pp.parseClassId = function (node, isStatement) { + node.id = this.type === _tokentype.types.name ? this.parseIdent() : isStatement ? this.unexpected() : null; +}; + +pp.parseClassSuper = function (node) { + node.superClass = this.eat(_tokentype.types._extends) ? this.parseExprSubscripts() : null; +}; + +// Parses module export declaration. + +pp.parseExport = function (node) { + this.next(); + // export * from '...' + if (this.eat(_tokentype.types.star)) { + this.expectContextual("from"); + node.source = this.type === _tokentype.types.string ? this.parseExprAtom() : this.unexpected(); + this.semicolon(); + return this.finishNode(node, "ExportAllDeclaration"); + } + if (this.eat(_tokentype.types._default)) { + // export default ... + var expr = this.parseMaybeAssign(); + var needsSemi = true; + if (expr.type == "FunctionExpression" || expr.type == "ClassExpression") { + needsSemi = false; + if (expr.id) { + expr.type = expr.type == "FunctionExpression" ? "FunctionDeclaration" : "ClassDeclaration"; + } + } + node.declaration = expr; + if (needsSemi) this.semicolon(); + return this.finishNode(node, "ExportDefaultDeclaration"); + } + // export var|const|let|function|class ... + if (this.shouldParseExportStatement()) { + node.declaration = this.parseStatement(true); + node.specifiers = []; + node.source = null; + } else { + // export { x, y as z } [from '...'] + node.declaration = null; + node.specifiers = this.parseExportSpecifiers(); + if (this.eatContextual("from")) { + node.source = this.type === _tokentype.types.string ? this.parseExprAtom() : this.unexpected(); + } else { + node.source = null; + } + this.semicolon(); + } + return this.finishNode(node, "ExportNamedDeclaration"); +}; + +pp.shouldParseExportStatement = function () { + return this.type.keyword; +}; + +// Parses a comma-separated list of module exports. + +pp.parseExportSpecifiers = function () { + var nodes = [], + first = true; + // export { x, y as z } [from '...'] + this.expect(_tokentype.types.braceL); + while (!this.eat(_tokentype.types.braceR)) { + if (!first) { + this.expect(_tokentype.types.comma); + if (this.afterTrailingComma(_tokentype.types.braceR)) break; + } else first = false; + + var node = this.startNode(); + node.local = this.parseIdent(this.type === _tokentype.types._default); + node.exported = this.eatContextual("as") ? this.parseIdent(true) : node.local; + nodes.push(this.finishNode(node, "ExportSpecifier")); + } + return nodes; +}; + +// Parses import declaration. + +pp.parseImport = function (node) { + this.next(); + // import '...' + if (this.type === _tokentype.types.string) { + node.specifiers = empty; + node.source = this.parseExprAtom(); + node.kind = ""; + } else { + node.specifiers = this.parseImportSpecifiers(); + this.expectContextual("from"); + node.source = this.type === _tokentype.types.string ? this.parseExprAtom() : this.unexpected(); + } + this.semicolon(); + return this.finishNode(node, "ImportDeclaration"); +}; + +// Parses a comma-separated list of module imports. + +pp.parseImportSpecifiers = function () { + var nodes = [], + first = true; + if (this.type === _tokentype.types.name) { + // import defaultObj, { x, y as z } from '...' + var node = this.startNode(); + node.local = this.parseIdent(); + this.checkLVal(node.local, true); + nodes.push(this.finishNode(node, "ImportDefaultSpecifier")); + if (!this.eat(_tokentype.types.comma)) return nodes; + } + if (this.type === _tokentype.types.star) { + var node = this.startNode(); + this.next(); + this.expectContextual("as"); + node.local = this.parseIdent(); + this.checkLVal(node.local, true); + nodes.push(this.finishNode(node, "ImportNamespaceSpecifier")); + return nodes; + } + this.expect(_tokentype.types.braceL); + while (!this.eat(_tokentype.types.braceR)) { + if (!first) { + this.expect(_tokentype.types.comma); + if (this.afterTrailingComma(_tokentype.types.braceR)) break; + } else first = false; + + var node = this.startNode(); + node.imported = this.parseIdent(true); + node.local = this.eatContextual("as") ? this.parseIdent() : node.imported; + this.checkLVal(node.local, true); + nodes.push(this.finishNode(node, "ImportSpecifier")); + } + return nodes; +}; + +},{"./state":10,"./tokentype":14,"./whitespace":16}],12:[function(_dereq_,module,exports){ +// The algorithm used to determine whether a regexp can appear at a +// given point in the program is loosely based on sweet.js' approach. +// See https://github.com/mozilla/sweet.js/wiki/design + +"use strict"; + +exports.__esModule = true; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var _state = _dereq_("./state"); + +var _tokentype = _dereq_("./tokentype"); + +var _whitespace = _dereq_("./whitespace"); + +var TokContext = function TokContext(token, isExpr, preserveSpace, override) { + _classCallCheck(this, TokContext); + + this.token = token; + this.isExpr = !!isExpr; + this.preserveSpace = !!preserveSpace; + this.override = override; +}; + +exports.TokContext = TokContext; +var types = { + b_stat: new TokContext("{", false), + b_expr: new TokContext("{", true), + b_tmpl: new TokContext("${", true), + p_stat: new TokContext("(", false), + p_expr: new TokContext("(", true), + q_tmpl: new TokContext("`", true, true, function (p) { + return p.readTmplToken(); + }), + f_expr: new TokContext("function", true) +}; + +exports.types = types; +var pp = _state.Parser.prototype; + +pp.initialContext = function () { + return [types.b_stat]; +}; + +pp.braceIsBlock = function (prevType) { + if (prevType === _tokentype.types.colon) { + var _parent = this.curContext(); + if (_parent === types.b_stat || _parent === types.b_expr) return !_parent.isExpr; + } + if (prevType === _tokentype.types._return) return _whitespace.lineBreak.test(this.input.slice(this.lastTokEnd, this.start)); + if (prevType === _tokentype.types._else || prevType === _tokentype.types.semi || prevType === _tokentype.types.eof || prevType === _tokentype.types.parenR) return true; + if (prevType == _tokentype.types.braceL) return this.curContext() === types.b_stat; + return !this.exprAllowed; +}; + +pp.updateContext = function (prevType) { + var update = undefined, + type = this.type; + if (type.keyword && prevType == _tokentype.types.dot) this.exprAllowed = false;else if (update = type.updateContext) update.call(this, prevType);else this.exprAllowed = type.beforeExpr; +}; + +// Token-specific context update code + +_tokentype.types.parenR.updateContext = _tokentype.types.braceR.updateContext = function () { + if (this.context.length == 1) { + this.exprAllowed = true; + return; + } + var out = this.context.pop(); + if (out === types.b_stat && this.curContext() === types.f_expr) { + this.context.pop(); + this.exprAllowed = false; + } else if (out === types.b_tmpl) { + this.exprAllowed = true; + } else { + this.exprAllowed = !out.isExpr; + } +}; + +_tokentype.types.braceL.updateContext = function (prevType) { + this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr); + this.exprAllowed = true; +}; + +_tokentype.types.dollarBraceL.updateContext = function () { + this.context.push(types.b_tmpl); + this.exprAllowed = true; +}; + +_tokentype.types.parenL.updateContext = function (prevType) { + var statementParens = prevType === _tokentype.types._if || prevType === _tokentype.types._for || prevType === _tokentype.types._with || prevType === _tokentype.types._while; + this.context.push(statementParens ? types.p_stat : types.p_expr); + this.exprAllowed = true; +}; + +_tokentype.types.incDec.updateContext = function () {}; + +_tokentype.types._function.updateContext = function () { + if (this.curContext() !== types.b_stat) this.context.push(types.f_expr); + this.exprAllowed = false; +}; + +_tokentype.types.backQuote.updateContext = function () { + if (this.curContext() === types.q_tmpl) this.context.pop();else this.context.push(types.q_tmpl); + this.exprAllowed = false; +}; + +// tokExprAllowed stays unchanged + +},{"./state":10,"./tokentype":14,"./whitespace":16}],13:[function(_dereq_,module,exports){ +"use strict"; + +exports.__esModule = true; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var _identifier = _dereq_("./identifier"); + +var _tokentype = _dereq_("./tokentype"); + +var _state = _dereq_("./state"); + +var _locutil = _dereq_("./locutil"); + +var _whitespace = _dereq_("./whitespace"); + +// Object type used to represent tokens. Note that normally, tokens +// simply exist as properties on the parser object. This is only +// used for the onToken callback and the external tokenizer. + +var Token = function Token(p) { + _classCallCheck(this, Token); + + this.type = p.type; + this.value = p.value; + this.start = p.start; + this.end = p.end; + if (p.options.locations) this.loc = new _locutil.SourceLocation(p, p.startLoc, p.endLoc); + if (p.options.ranges) this.range = [p.start, p.end]; +}; + +exports.Token = Token; + +// ## Tokenizer + +var pp = _state.Parser.prototype; + +// Are we running under Rhino? +var isRhino = typeof Packages == "object" && Object.prototype.toString.call(Packages) == "[object JavaPackage]"; + +// Move to the next token + +pp.next = function () { + if (this.options.onToken) this.options.onToken(new Token(this)); + + this.lastTokEnd = this.end; + this.lastTokStart = this.start; + this.lastTokEndLoc = this.endLoc; + this.lastTokStartLoc = this.startLoc; + this.nextToken(); +}; + +pp.getToken = function () { + this.next(); + return new Token(this); +}; + +// If we're in an ES6 environment, make parsers iterable +if (typeof Symbol !== "undefined") pp[Symbol.iterator] = function () { + var self = this; + return { next: function next() { + var token = self.getToken(); + return { + done: token.type === _tokentype.types.eof, + value: token + }; + } }; +}; + +// Toggle strict mode. Re-reads the next number or string to please +// pedantic tests (`"use strict"; 010;` should fail). + +pp.setStrict = function (strict) { + this.strict = strict; + if (this.type !== _tokentype.types.num && this.type !== _tokentype.types.string) return; + this.pos = this.start; + if (this.options.locations) { + while (this.pos < this.lineStart) { + this.lineStart = this.input.lastIndexOf("\n", this.lineStart - 2) + 1; + --this.curLine; + } + } + this.nextToken(); +}; + +pp.curContext = function () { + return this.context[this.context.length - 1]; +}; + +// Read a single token, updating the parser object's token-related +// properties. + +pp.nextToken = function () { + var curContext = this.curContext(); + if (!curContext || !curContext.preserveSpace) this.skipSpace(); + + this.start = this.pos; + if (this.options.locations) this.startLoc = this.curPosition(); + if (this.pos >= this.input.length) return this.finishToken(_tokentype.types.eof); + + if (curContext.override) return curContext.override(this);else this.readToken(this.fullCharCodeAtPos()); +}; + +pp.readToken = function (code) { + // Identifier or keyword. '\uXXXX' sequences are allowed in + // identifiers, so '\' also dispatches to that. + if (_identifier.isIdentifierStart(code, this.options.ecmaVersion >= 6) || code === 92 /* '\' */) return this.readWord(); + + return this.getTokenFromCode(code); +}; + +pp.fullCharCodeAtPos = function () { + var code = this.input.charCodeAt(this.pos); + if (code <= 0xd7ff || code >= 0xe000) return code; + var next = this.input.charCodeAt(this.pos + 1); + return (code << 10) + next - 0x35fdc00; +}; + +pp.skipBlockComment = function () { + var startLoc = this.options.onComment && this.curPosition(); + var start = this.pos, + end = this.input.indexOf("*/", this.pos += 2); + if (end === -1) this.raise(this.pos - 2, "Unterminated comment"); + this.pos = end + 2; + if (this.options.locations) { + _whitespace.lineBreakG.lastIndex = start; + var match = undefined; + while ((match = _whitespace.lineBreakG.exec(this.input)) && match.index < this.pos) { + ++this.curLine; + this.lineStart = match.index + match[0].length; + } + } + if (this.options.onComment) this.options.onComment(true, this.input.slice(start + 2, end), start, this.pos, startLoc, this.curPosition()); +}; + +pp.skipLineComment = function (startSkip) { + var start = this.pos; + var startLoc = this.options.onComment && this.curPosition(); + var ch = this.input.charCodeAt(this.pos += startSkip); + while (this.pos < this.input.length && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) { + ++this.pos; + ch = this.input.charCodeAt(this.pos); + } + if (this.options.onComment) this.options.onComment(false, this.input.slice(start + startSkip, this.pos), start, this.pos, startLoc, this.curPosition()); +}; + +// Called at the start of the parse and after every token. Skips +// whitespace and comments, and. + +pp.skipSpace = function () { + loop: while (this.pos < this.input.length) { + var ch = this.input.charCodeAt(this.pos); + switch (ch) { + case 32:case 160: + // ' ' + ++this.pos; + break; + case 13: + if (this.input.charCodeAt(this.pos + 1) === 10) { + ++this.pos; + } + case 10:case 8232:case 8233: + ++this.pos; + if (this.options.locations) { + ++this.curLine; + this.lineStart = this.pos; + } + break; + case 47: + // '/' + switch (this.input.charCodeAt(this.pos + 1)) { + case 42: + // '*' + this.skipBlockComment(); + break; + case 47: + this.skipLineComment(2); + break; + default: + break loop; + } + break; + default: + if (ch > 8 && ch < 14 || ch >= 5760 && _whitespace.nonASCIIwhitespace.test(String.fromCharCode(ch))) { + ++this.pos; + } else { + break loop; + } + } + } +}; + +// Called at the end of every token. Sets `end`, `val`, and +// maintains `context` and `exprAllowed`, and skips the space after +// the token, so that the next one's `start` will point at the +// right position. + +pp.finishToken = function (type, val) { + this.end = this.pos; + if (this.options.locations) this.endLoc = this.curPosition(); + var prevType = this.type; + this.type = type; + this.value = val; + + this.updateContext(prevType); +}; + +// ### Token reading + +// This is the function that is called to fetch the next token. It +// is somewhat obscure, because it works in character codes rather +// than characters, and because operator parsing has been inlined +// into it. +// +// All in the name of speed. +// +pp.readToken_dot = function () { + var next = this.input.charCodeAt(this.pos + 1); + if (next >= 48 && next <= 57) return this.readNumber(true); + var next2 = this.input.charCodeAt(this.pos + 2); + if (this.options.ecmaVersion >= 6 && next === 46 && next2 === 46) { + // 46 = dot '.' + this.pos += 3; + return this.finishToken(_tokentype.types.ellipsis); + } else { + ++this.pos; + return this.finishToken(_tokentype.types.dot); + } +}; + +pp.readToken_slash = function () { + // '/' + var next = this.input.charCodeAt(this.pos + 1); + if (this.exprAllowed) { + ++this.pos;return this.readRegexp(); + } + if (next === 61) return this.finishOp(_tokentype.types.assign, 2); + return this.finishOp(_tokentype.types.slash, 1); +}; + +pp.readToken_mult_modulo = function (code) { + // '%*' + var next = this.input.charCodeAt(this.pos + 1); + if (next === 61) return this.finishOp(_tokentype.types.assign, 2); + return this.finishOp(code === 42 ? _tokentype.types.star : _tokentype.types.modulo, 1); +}; + +pp.readToken_pipe_amp = function (code) { + // '|&' + var next = this.input.charCodeAt(this.pos + 1); + if (next === code) return this.finishOp(code === 124 ? _tokentype.types.logicalOR : _tokentype.types.logicalAND, 2); + if (next === 61) return this.finishOp(_tokentype.types.assign, 2); + return this.finishOp(code === 124 ? _tokentype.types.bitwiseOR : _tokentype.types.bitwiseAND, 1); +}; + +pp.readToken_caret = function () { + // '^' + var next = this.input.charCodeAt(this.pos + 1); + if (next === 61) return this.finishOp(_tokentype.types.assign, 2); + return this.finishOp(_tokentype.types.bitwiseXOR, 1); +}; + +pp.readToken_plus_min = function (code) { + // '+-' + var next = this.input.charCodeAt(this.pos + 1); + if (next === code) { + if (next == 45 && this.input.charCodeAt(this.pos + 2) == 62 && _whitespace.lineBreak.test(this.input.slice(this.lastTokEnd, this.pos))) { + // A `-->` line comment + this.skipLineComment(3); + this.skipSpace(); + return this.nextToken(); + } + return this.finishOp(_tokentype.types.incDec, 2); + } + if (next === 61) return this.finishOp(_tokentype.types.assign, 2); + return this.finishOp(_tokentype.types.plusMin, 1); +}; + +pp.readToken_lt_gt = function (code) { + // '<>' + var next = this.input.charCodeAt(this.pos + 1); + var size = 1; + if (next === code) { + size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2; + if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(_tokentype.types.assign, size + 1); + return this.finishOp(_tokentype.types.bitShift, size); + } + if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 && this.input.charCodeAt(this.pos + 3) == 45) { + if (this.inModule) this.unexpected(); + // `` line comment - this.skipLineComment(3); - this.skipSpace(); - return this.nextToken(); - } - return this.finishOp(tt.incDec, 2); - } - if (next === 61) return this.finishOp(tt.assign, 2); - return this.finishOp(tt.plusMin, 1); -}; + return map; + }; -pp.readToken_lt_gt = function (code) { - // '<>' - var next = this.input.charCodeAt(this.pos + 1); - var size = 1; - if (next === code) { - size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2; - if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1); - return this.finishOp(tt.bitShift, size); - } - if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 && this.input.charCodeAt(this.pos + 3) == 45) { - if (this.inModule) this.unexpected(); - // `` line comment - this.skipLineComment(3); - this.skipSpace(); - return this.nextToken(); - } - return this.finishOp(_tokentype.types.incDec, 2); - } - if (next === 61) return this.finishOp(_tokentype.types.assign, 2); - return this.finishOp(_tokentype.types.plusMin, 1); -}; - -pp.readToken_lt_gt = function (code) { - // '<>' - var next = this.input.charCodeAt(this.pos + 1); - var size = 1; - if (next === code) { - size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2; - if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(_tokentype.types.assign, size + 1); - return this.finishOp(_tokentype.types.bitShift, size); - } - if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 && this.input.charCodeAt(this.pos + 3) == 45) { - if (this.inModule) this.unexpected(); - // `/lib/jquery-ui.css"> -/lib/jquery-ui-slider-pips.css"> - - - - - - - -
- - - - \ No newline at end of file From 7c9f5ec959931c207b0ba442394b7180183bdff3 Mon Sep 17 00:00:00 2001 From: Amanda Date: Mon, 10 Aug 2015 17:32:45 -0400 Subject: [PATCH 190/199] Responded to Bob's comments --- content/src/draw-protractor.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/content/src/draw-protractor.js b/content/src/draw-protractor.js index 8d245f4d..bb3a455d 100644 --- a/content/src/draw-protractor.js +++ b/content/src/draw-protractor.js @@ -6,7 +6,7 @@ var $ = require('jquery'), jqueryturtle = require('jquery-turtle'), see = require('see'); -var t; +//var t; eval(see.scope('drawProtractor')); function to360(v) { while (v < 0) { @@ -16,6 +16,7 @@ function to360(v) { } function renderProtractor(canvas, step) { + var t; var ctx = canvas[0].getContext('2d'); ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.clearRect(0, 0, canvas.width(), canvas.height()); @@ -30,7 +31,7 @@ function renderProtractor(canvas, step) { t.rt(step.endCoords.direction); } - if (step.command == "lt") { + else if (step.command == "lt") { t.lt(step.endCoords.direction); } } From 653f2fcff12c3cb287e0f40b8db4471ae6812abd Mon Sep 17 00:00:00 2001 From: calistenson Date: Tue, 11 Aug 2015 13:28:45 -0400 Subject: [PATCH 191/199] Created update_arrows function, simplified how block_mode var was created, and fixed a few spacing issues --- content/src/arrows.js | 36 ++++++++-------- content/src/debug.js | 95 ++++++++++++++----------------------------- content/src/view.js | 4 +- 3 files changed, 50 insertions(+), 85 deletions(-) diff --git a/content/src/arrows.js b/content/src/arrows.js index 1841ef86..667455d1 100644 --- a/content/src/arrows.js +++ b/content/src/arrows.js @@ -7,15 +7,12 @@ var $ = require('jquery'); function curvedVertical(x1, y1, x2, y2) { - y2 = y2 - 12; - x1 = parseFloat(x1); y1 = parseFloat(y1); x2 = parseFloat(x2); y2 = parseFloat(y2); var radius = Math.abs(y1 - y2); - return 'M'+ x1 + "," + y1 + " " + 'A'+ radius + "," + radius + " 1 0,1 " + x2 + "," + y2; }; @@ -31,8 +28,9 @@ function drawArrow(show_fade, startcoords, endcoords, x_val, offset_left, offset + offset_left, (endcoords.pageY - offset_top)) + "' marker-start='url(#arrowhead2)' style='stroke:#8EC8FF;fill:none; stroke-width:4' position='relative'/> \ " } else{ - arrowtext = " \ " + arrowtext = " \ " } var text = " "; - var div = document.createElement('div'); - div.className = "arrow"; - div.innerHTML = text; - div.style.visibility = 'visible'; - div.style.position = "absolute"; - div.style.zIndex = "10"; - div.style.left = "0px"; - div.style.top = "0px"; - - if (block_mode) { - $("div[id^='editor_'] .droplet-main-scroller").append(div); - } else { - $("div[id^='editor_']").append(div); - } + var div = document.createElement('div'); + div.className = "arrow"; + div.innerHTML = text; + div.style.visibility = 'visible'; + div.style.position = "absolute"; + div.style.zIndex = "10"; + div.style.left = "0px"; + div.style.top = "0px"; + + if (block_mode) { + $("div[id^='editor_'] .droplet-main-scroller").append(div); + } else { + $("div[id^='editor_']").append(div); + } }; module.exports = {drawArrow : drawArrow}; \ No newline at end of file diff --git a/content/src/debug.js b/content/src/debug.js index 9d1a67d1..5a5a8741 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -404,24 +404,7 @@ function reportAppear(method, debugId, length, coordId, elem, args){ // decide if it is necessary to draw add and draw any arrows. if (currentLine < prevLine && currentIndex == prevIndex + 1) { - - if (arrows[prevIndex] != null) { - arrows[prevIndex]['after'] = {first: currentLocation, second: prevLocation}; - } else { - arrows[prevIndex] = {before: null, after: {first: currentLocation, second: prevLocation}}; - } - if (arrows[currentIndex] != null) { - arrows[currentIndex]['before'] = {first: currentLocation, second: prevLocation}; - } else{ - arrows[currentIndex] = {before: {first: currentLocation, second: prevLocation}, after : null}; - } - //Draw an arrow if the debugger is on - if (debugMode) { - view.arrow(view.paneid('left'), arrows, currentIndex, false); - } - if (!arrows[currentRecordID]){ - debugRecordsByLineNo[currentLine] = currentRecordID; - } + update_arrows(prevIndex, currentIndex); } traceLine(currentIndex); tracedIndex = currentIndex; @@ -437,27 +420,8 @@ function reportAppear(method, debugId, length, coordId, elem, args){ untraceLine(tracedIndex); tracedIndex = -1; } - if (line < prevLine && index == prevIndex + 1){ - - prevLocation = traceEvents[prevIndex].location; - - if (arrows[prevIndex] != null){ - arrows[prevIndex]['after'] = {first: currentLocation, second: prevLocation}; - } else{ - arrows[prevIndex] = {before: null, after: {first: currentLocation, second: prevLocation}}; - } - if (arrows[index] != null){ - arrows[index]['before'] = {first: currentLocation, second: prevLocation}; - } else{ - arrows[index] = {before: {first: currentLocation, second: prevLocation}, after : null}; - } - //Draw an arrow if the debugger is on - if (debugMode) { - view.arrow(view.paneid('left'), arrows, currentIndex, false); - } - if (!arrows[currentRecordID]){ - debugRecordsByLineNo[currentLine] = currentRecordID; - } + if (line < prevLine && index == prevIndex + 1){ + update_arrows(prevIndex, index); } traceLine(index); currentRecordID = debugId; @@ -519,25 +483,8 @@ function end_program(){ untraceLine(tracedIndex); tracedIndex = -1; } - if(currentLine < prevLine && currentIndex == prevIndex + 1){ - - if (arrows[prevIndex] != null){ - arrows[prevIndex]['after'] = {first: currentLocation, second: prevLocation}; - } else{ - arrows[prevIndex] = {before: null, after: {first: currentLocation, second: prevLocation}}; - } - if (arrows[currentIndex] != null){ - arrows[currentIndex]['before'] = {first: currentLocation, second: prevLocation}; - } else{ - arrows[currentIndex] = {before: {first: currentLocation, second: prevLocation}, after : null}; - } - if (!arrows[currentRecordID]){ - debugRecordsByLineNo[currentLine] = currentRecordID; - } - //Draw an arrow if the debugger is on - if (debugMode) { - view.arrow(view.paneid('left'), arrows, currentIndex, false); - } + if (currentLine < prevLine && currentIndex == prevIndex + 1) { + update_arrows(prevIndex, currentIndex); } traceLine(currentIndex); tracedIndex = currentIndex; @@ -626,9 +573,7 @@ function parseTurtleTransform(transform) { function traceLine(lineIndex) { var line = traceEvents[lineIndex].location.first_line; var prevLine = -1; - var block_mode = true; - - if (!view.getPaneEditorBlockMode(view.paneid("left"))){block_mode = false;} + var block_mode = view.getPaneEditorBlockMode(view.paneid("left")); if (traceEvents[lineIndex-1]){ prevLine = traceEvents[lineIndex-1].location.first_line; @@ -650,9 +595,7 @@ function traceLine(lineIndex) { function untraceLine(lineIndex) { var line = traceEvents[lineIndex].location.first_line; var prevLine = -1; - var block_mode = true; - - if (!view.getPaneEditorBlockMode(view.paneid("left"))){block_mode = false;} + var block_mode = view.getPaneEditorBlockMode(view.paneid("left")); if (traceEvents[lineIndex-1]){ prevLine = traceEvents[lineIndex-1].location.first_line; @@ -839,6 +782,30 @@ view.on('icehover', function(pane, ev) { } }); +function update_arrows(prevIndex, currentIndex) { + var prevLocation = traceEvents[prevIndex].location; + var currentLocation = traceEvents[currentIndex].location; + var currentLine = currentLocation.first_line; + + if (arrows[prevIndex] != null) { + arrows[prevIndex]['after'] = {first: currentLocation, second: prevLocation}; + } else { + arrows[prevIndex] = {before: null, after: {first: currentLocation, second: prevLocation}}; + } + if (arrows[currentIndex] != null) { + arrows[currentIndex]['before'] = {first: currentLocation, second: prevLocation}; + } else { + arrows[currentIndex] = {before: {first: currentLocation, second: prevLocation}, after : null}; + } + if (!arrows[currentRecordID]) { + debugRecordsByLineNo[currentLine] = currentRecordID; + } + //Draw an arrow if the debugger is on + if (debugMode) { + view.arrow(view.paneid('left'), arrows, currentIndex, false); + } +} + function convertCoords(origin, astransform) { if (!origin) { return null; } if (!astransform || !astransform.transform) { return null; } diff --git a/content/src/view.js b/content/src/view.js index 71881298..395013b8 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -3422,9 +3422,9 @@ function showVar(pane, lineNum, name, value, argsString) { div.style.top = String(coords.pageY - offsetTop) + "px"; if (blockMode) { - $("div[id^='editor_'] .droplet-main-scroller").append(div); + $("div[id^='editor_'] ").append(div); // .droplet-main-scroller } else { - $("div[id^='editor_']").append(div); + $("div[id^='editor_']").append(div); } } } From 73ca6971b59f61d2ebd5257dceb940be45e79535 Mon Sep 17 00:00:00 2001 From: calistenson Date: Fri, 14 Aug 2015 10:04:05 -0400 Subject: [PATCH 192/199] Updated arrows to have a redraw function. Did not fix the shaking in text mode scroll or the cut off in droplet. Looking for other ways to solve this problem --- content/src/arrows.js | 28 +++++++++++++++++----------- content/src/view.js | 29 ++++++++++++----------------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/content/src/arrows.js b/content/src/arrows.js index 667455d1..cda36a49 100644 --- a/content/src/arrows.js +++ b/content/src/arrows.js @@ -13,27 +13,33 @@ function curvedVertical(x1, y1, x2, y2) { x2 = parseFloat(x2); y2 = parseFloat(y2); var radius = Math.abs(y1 - y2); - return 'M'+ x1 + "," + y1 + " " + 'A'+ radius + "," + radius + " 1 0,1 " + x2 + "," + y2; + return "M"+ x1 + "," + y1 + " " + "A"+ radius + "," + radius + " 1 0,1 " + x2 + "," + y2; }; -function drawArrow(show_fade, startcoords, endcoords, x_val, offset_left, offset_top, block_mode){ +function redrawArrow(show_fade, startcoords, endcoords, x_val, offset_left, offset_top, block_mode) { + + var path_data = curvedVertical(x_val + offset_left, (startcoords.pageY - offset_top), x_val + + offset_left, (endcoords.pageY - offset_top)); + $("#drawnArrow").attr("d", path_data); +} + +function drawArrow(show_fade, startcoords, endcoords, x_val, offset_left, offset_top, block_mode) { /* Given the coordinates and offsets, arrows are drawn with an svg path element that creates an upward left-facing curve to the right of the blocks/text code from the previous line of code that ran to the current line that's running. Note that arrows are drawn on the condition that there's an out of order flow in lines of code. i.e., line 5 runs and then line 2 runs. */ - if (show_fade) { - arrowtext = " \ " - } else{ - arrowtext = " \ " + } else { + arrowtext = " \ " + + "' marker-start='url(#arrowhead1)' style='stroke:dodgerblue; fill:none; stroke-width:4'; position:'fixed'/> \ " } - var text = " \ 0) { + arrows.redrawArrow(show_fade, startcoords, endcoords, x_val, offset_left, offset_top, block_mode); + } else { + arrows.drawArrow(show_fade, startcoords, endcoords, x_val, offset_left, offset_top, block_mode); + } + } } function showVar(pane, lineNum, name, value, argsString) { @@ -3422,7 +3417,7 @@ function showVar(pane, lineNum, name, value, argsString) { div.style.top = String(coords.pageY - offsetTop) + "px"; if (blockMode) { - $("div[id^='editor_'] ").append(div); // .droplet-main-scroller + $("div[id^='editor_'] .droplet-main-scroller").append(div); } else { $("div[id^='editor_']").append(div); } From b2b21cb56ba7339e28698e10eea74159c67a4dbb Mon Sep 17 00:00:00 2001 From: calistenson Date: Fri, 14 Aug 2015 10:20:55 -0400 Subject: [PATCH 193/199] Cleared logging statements, added comments, fixed some indendation --- content/src/arrows.js | 5 +- content/src/view.js | 114 +++++++++++++++++++++--------------------- 2 files changed, 60 insertions(+), 59 deletions(-) diff --git a/content/src/arrows.js b/content/src/arrows.js index cda36a49..de852a35 100644 --- a/content/src/arrows.js +++ b/content/src/arrows.js @@ -7,6 +7,9 @@ var $ = require('jquery'); function curvedVertical(x1, y1, x2, y2) { + /* This function takes two coordinates and calculates an SVG path + that is used for the curve of the arrows drawn on the code. + */ y2 = y2 - 12; x1 = parseFloat(x1); y1 = parseFloat(y1); @@ -17,7 +20,7 @@ function curvedVertical(x1, y1, x2, y2) { }; function redrawArrow(show_fade, startcoords, endcoords, x_val, offset_left, offset_top, block_mode) { - + /* When the page scrolls we redraw arrows by recalculating the paths and reseting the path data*/ var path_data = curvedVertical(x_val + offset_left, (startcoords.pageY - offset_top), x_val + offset_left, (endcoords.pageY - offset_top)); $("#drawnArrow").attr("d", path_data); diff --git a/content/src/view.js b/content/src/view.js index 02b42d20..3c75f3db 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -240,57 +240,57 @@ function removeSlider() { } function initializeSlider (linenoList) { - // Create div element for scrubbber - var div = document.createElement('div'); - div.className = 'scrubber'; - var backDiv = document.createElement('div'); - var forwardDiv = document.createElement('div'); - var sliderDiv = document.createElement('div'); - sliderDiv.id = 'slider'; - // Append the newly created div for the slider to the panel at bottom - $(".scrubbermark").append(div); - $(".scrubber").append(sliderDiv); - - backDiv.innerHTML = " "; - $(".scrubber").append(backDiv); - - forwardDiv = document.createElement('div'); - forwardDiv.innerHTML = ""; + // Create div element for scrubbber + var div = document.createElement('div'); + div.className = 'scrubber'; + var backDiv = document.createElement('div'); + var forwardDiv = document.createElement('div'); + var sliderDiv = document.createElement('div'); + sliderDiv.id = 'slider'; + // Append the newly created div for the slider to the panel at bottom + $(".scrubbermark").append(div); + $(".scrubber").append(sliderDiv); + + backDiv.innerHTML = ""; + $(".scrubber").append(backDiv); + + forwardDiv = document.createElement('div'); + forwardDiv.innerHTML = ""; - $(".scrubber").append(forwardDiv); - - $('#backButton').tooltipster({ - content: "back a step" - }); - $('#forwardButton').tooltipster({ - content: "forward a step" - }) + $(".scrubber").append(forwardDiv); - var label = document.createElement('div'); - label.id = 'label'; - label.innerHTML = ""; - $(".scrubber").append(label); - - // Jquery-ui slider implementation - $(function() { - $("#slider").slider({ - min: 0, - max: linenoList.length - 1, - step: 1, - range: "min", - smooth: false - }) - .slider("pips", { - first: "pip", - rest: "pip", - last: "pip" - }) - .slider("float", { - labels: linenoList, - prefix: "Line " + $('#backButton').tooltipster({ + content: "back a step" + }); + $('#forwardButton').tooltipster({ + content: "forward a step" + }) + + var label = document.createElement('div'); + label.id = 'label'; + label.innerHTML = ""; + $(".scrubber").append(label); + + // Jquery-ui slider implementation + $(function() { + $("#slider").slider({ + min: 0, + max: linenoList.length - 1, + step: 1, + range: "min", + smooth: false }) - }); - $('#label').text('Step ' + ($("#slider").slider("value") + 1) + ' of ' + linenoList.length + ' Steps'); + .slider("pips", { + first: "pip", + rest: "pip", + last: "pip" + }) + .slider("float", { + labels: linenoList, + prefix: "Line " + }) + }); + $('#label').text('Step ' + ($("#slider").slider("value") + 1) + ' of ' + linenoList.length + ' Steps'); } function createSlider(linenoList) { @@ -481,15 +481,15 @@ function flashNotification(text, loading) { $('#notification').removeClass(); } $('#notification').html(text).data('marker', marker).finish() - .css({opacity: 0,display: 'inline-block'}) - .css({left:($(window).width() - $('#notification').outerWidth()) / 2}) - .animate({opacity:1}, 200) - .queue(function(n) { - $('body').off('.flashNotification'); - $(window).off('.flashNotification'); - $('body').on('blur.flashNotification ' + + .css({opacity: 0,display: 'inline-block'}) + .css({left:($(window).width() - $('#notification').outerWidth()) / 2}) + .animate({opacity:1}, 200) + .queue(function(n) { + $('body').off('.flashNotification'); + $(window).off('.flashNotification'); + $('body').on('blur.flashNotification ' + 'mousedown.flashNotification keydown.flashNotification', hidefunc); - $(window).on('resize.flashNotification ' + + $(window).on('resize.flashNotification ' + 'popstate.flashNotification', hidefunc); n(); }); @@ -3334,7 +3334,6 @@ function arrow(pane, arrow_list, traceEventNum, show_fade) { } } state.pane[pane].editor.getSession().on("changeScrollTop", function(e) { - console.log("scroll:" , e); coords_and_offsets(firstBeforeLoc, secondBeforeLoc, show_fade, block_mode, pane, dropletEditor); }); coords_and_offsets(firstBeforeLoc, secondBeforeLoc, show_fade, block_mode, pane, dropletEditor); @@ -3349,7 +3348,6 @@ function coords_and_offsets(firstLoc, secondLoc, show_fade, block_mode, pane, dr if (block_mode){ var startBounds = dropletEditor.getLineMetrics(firstLoc.first_line - 1); var endBounds = dropletEditor.getLineMetrics(secondLoc.first_line - 1); - console.log("endBounds: ", endBounds); startcoords = {pageX : startBounds.bounds.x, pageY: startBounds.bounds.y - startBounds.bounds.height/2}; endcoords = {pageX : endBounds.bounds.x, pageY: endBounds.bounds.y + endBounds.bounds.height/4}; offset_top = startBounds.bounds.height - $(".editor").offset().top; From d81b636b15e5f8a98d3b38cfc3dc8e06b3887cf6 Mon Sep 17 00:00:00 2001 From: calistenson Date: Fri, 14 Aug 2015 13:27:42 -0400 Subject: [PATCH 194/199] Fixed some trailing whitespace --- content/src/arrows.js | 23 ++++++++++------------- content/src/view.js | 21 ++++++++++----------- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/content/src/arrows.js b/content/src/arrows.js index de852a35..1cceff56 100644 --- a/content/src/arrows.js +++ b/content/src/arrows.js @@ -21,29 +21,28 @@ function curvedVertical(x1, y1, x2, y2) { function redrawArrow(show_fade, startcoords, endcoords, x_val, offset_left, offset_top, block_mode) { /* When the page scrolls we redraw arrows by recalculating the paths and reseting the path data*/ - var path_data = curvedVertical(x_val + offset_left, (startcoords.pageY - offset_top), x_val - + offset_left, (endcoords.pageY - offset_top)); + var path_data = curvedVertical(x_val + offset_left, (startcoords.pageY - offset_top), x_val + + offset_left, (endcoords.pageY - offset_top)); $("#drawnArrow").attr("d", path_data); } function drawArrow(show_fade, startcoords, endcoords, x_val, offset_left, offset_top, block_mode) { - /* Given the coordinates and offsets, arrows are drawn with an svg path element that creates an - upward left-facing curve to the right of the blocks/text code from the previous line of code that ran + /* Given the coordinates and offsets, arrows are drawn with an svg path element that creates an + upward left-facing curve to the right of the blocks/text code from the previous line of code that ran to the current line that's running. Note that arrows are drawn on the condition that there's an out of order flow in lines of code. i.e., line 5 runs and then line 2 runs. */ if (show_fade) { - arrowtext = " \ " } else { arrowtext = " \ " - } - - var text = " \ \ \ \ " + arrowtext + " "; - var div = document.createElement('div'); div.className = "arrow"; div.innerHTML = text; @@ -61,7 +59,6 @@ function drawArrow(show_fade, startcoords, endcoords, x_val, offset_left, offset div.style.zIndex = "10"; div.style.left = "0px"; div.style.top = "0px"; - if (block_mode) { $("div[id^='editor_'] .droplet-main-scroller").append(div); } else { diff --git a/content/src/view.js b/content/src/view.js index 3c75f3db..1b5d949d 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -91,11 +91,11 @@ ZeroClipboard.config({ window.pencilcode.view = { // Listens to events - on: function(tag, cb) { + on: function(tag, cb) { if (state.callbacks[tag] == null){ state.callbacks[tag] = [] } - state.callbacks[tag].push(cb); + state.callbacks[tag].push(cb); }, // Simulate firing of an event @@ -229,7 +229,7 @@ function paneid(position) { return $('.' + position).find('.pane').attr('id'); } -var sliderCreated = false; +var sliderCreated = false; function removeSlider() { $(".scrubber").remove(); @@ -257,7 +257,7 @@ function initializeSlider (linenoList) { forwardDiv = document.createElement('div'); forwardDiv.innerHTML = ""; - $(".scrubber").append(forwardDiv); + $(".scrubber").append(forwardDiv); $('#backButton').tooltipster({ content: "back a step" @@ -285,7 +285,7 @@ function initializeSlider (linenoList) { rest: "pip", last: "pip" }) - .slider("float", { + .slider("float", { labels: linenoList, prefix: "Line " }) @@ -304,7 +304,7 @@ function createSlider(linenoList) { // the slider has been created sliderCreated = true; - sizeHtmlCssPanels('bravo'); + sizeHtmlCssPanels('bravo'); } // if the slider has already been created and events are pushed, modify existing slider if (sliderCreated) { @@ -519,8 +519,7 @@ function flashButton(id) { // FILENAME AND RENAMING /////////////////////////////////////////////////////////////////////////// -function selectEndOf(contentEditableElement) -{ +function selectEndOf(contentEditableElement) { var range,selection; if (document.createRange) { range = document.createRange(); @@ -3030,7 +3029,7 @@ function markPaneEditorLine(pane, line, markclass) { // have applied the style on a particular line. var idMap = paneState.marked[markclass]; if (zline in idMap) { - return; // Nothing to do if already highlighted. + return; // Nothing to do if already highlighted. } if (/^gutter/.test(markclass)) { paneState.editor.session.addGutterDecoration(zline, markclass); @@ -3415,9 +3414,9 @@ function showVar(pane, lineNum, name, value, argsString) { div.style.top = String(coords.pageY - offsetTop) + "px"; if (blockMode) { - $("div[id^='editor_'] .droplet-main-scroller").append(div); + $("div[id^='editor_'] .droplet-main-scroller").append(div); } else { - $("div[id^='editor_']").append(div); + $("div[id^='editor_']").append(div); } } } From b4388133fd8114b197bdcc33d6527ff87f243519 Mon Sep 17 00:00:00 2001 From: calistenson Date: Fri, 14 Aug 2015 15:36:58 -0400 Subject: [PATCH 195/199] Fixed a bug with arrows in text mode --- content/src/arrows.js | 3 ++- content/src/view.js | 10 ++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/content/src/arrows.js b/content/src/arrows.js index 1cceff56..075b8d83 100644 --- a/content/src/arrows.js +++ b/content/src/arrows.js @@ -15,7 +15,8 @@ function curvedVertical(x1, y1, x2, y2) { y1 = parseFloat(y1); x2 = parseFloat(x2); y2 = parseFloat(y2); - var radius = Math.abs(y1 - y2); + var radius = parseFloat(Math.abs(y1 - y2)); + console.log("vals", x1, y1, x2, y2); return "M"+ x1 + "," + y1 + " " + "A"+ radius + "," + radius + " 1 0,1 " + x2 + "," + y2; }; diff --git a/content/src/view.js b/content/src/view.js index 1b5d949d..d483ad1a 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -3360,16 +3360,10 @@ function coords_and_offsets(firstLoc, secondLoc, show_fade, block_mode, pane, dr offset_left = $(".editor").offset().left + pixel_cushion; startcoords = state.pane[pane].editor.renderer.textToScreenCoordinates((firstLoc.first_line), (firstLoc.last_column + 10)); endcoords = state.pane[pane].editor.renderer.textToScreenCoordinates((secondLoc.first_line), (secondLoc.last_column + 10)); + console.log("Coords: ", startcoords, endcoords); startcoords.pageY = startcoords.pageY - font_size/2; endcoords.pageY = endcoords.pageY - font_size/2; - if (Math.abs(secondLoc.first_line - firstLoc.first_line) > 1) { - var x_val = 0; - if (startcoords.pageX > endcoords.pageX) { - x_val = startcoords.pageX; - } else { - x_val = endcoords.pageX; - } - } + var x_val = Math.max(startcoords.pageX, endcoords.pageX); } if ($("#drawnArrow").length > 0) { arrows.redrawArrow(show_fade, startcoords, endcoords, x_val, offset_left, offset_top, block_mode); From 0f746c32b7f58159c9de6faf67c0c37f6af46d4d Mon Sep 17 00:00:00 2001 From: Amanda Date: Fri, 14 Aug 2015 15:43:48 -0400 Subject: [PATCH 196/199] Removed trailing whitespace and fixed spacing --- content/src/debug.js | 64 +++++++++++++++++++---------------------- content/src/editor.less | 45 +++++++++++++++-------------- 2 files changed, 53 insertions(+), 56 deletions(-) diff --git a/content/src/debug.js b/content/src/debug.js index e0cea662..a3724e37 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -11,7 +11,6 @@ var $ = require('jquery'), util = require('util'); eval(see.scope('debug')); -resetDebugState(); var targetWindow = null; // window object of the frame being debugged. var untrackedVariables = []; // list of (mostly jquery-turtle) globals not to be tracked. var cachedParseStack = {}; // parsed stack traces for currently-running code. @@ -20,6 +19,7 @@ var stopButtonShown = 0; // 0 = not shown; 1 = shown; 2 = stopped. var currentSourceMap = null; // v3 source map for currently-running instrumented code. var sliderTimer = null; // detect if there is existing timer var debugMode = true; // user has debug mode turned on +resetDebugState(); // reset debugging state // verification of complexity of stuck loop var stuckComplexity = { @@ -122,9 +122,7 @@ var debug = window.ide = { view.publish('error', [simpleData]); } }, - stopButton: stopButton, - getEditorText: function() { var doc = view.getPaneEditorData(view.paneid('left')); if (doc) { @@ -145,7 +143,6 @@ var debug = window.ide = { }, trace: function(event, data) { detectStuckProgram(); - if (event.type === 'before' || event.type === 'enter') { currentDebugId += 1; var record = {line: 0, eventIndex: null, startCoords: [], endCoords: [], method: "", @@ -160,7 +157,7 @@ var debug = window.ide = { } record.line = lineno; debugRecordsByDebugId[currentDebugId] = record; - if (!debugRecordsByLineNo[lineno]){ + if (!debugRecordsByLineNo[lineno]) { debugRecordsByLineNo[lineno] = currentDebugId; } updateVariables(event.location.first_line, currentDebugId, event.vars); @@ -186,7 +183,6 @@ function setupSlider() { sliderTimer = null; } sliderTime = setTimeout(function() {view.createSlider(linenoList)}, 1000); - } @@ -353,21 +349,19 @@ var showPopupErrorMessage = function (msg) { center.innerHTML = msg; } -function reportSeeeval(method, debugId, length, coordId, elem, args){ +function reportSeeeval(method, debugId, length, coordId, elem, args) { currentDebugId += 1; record = {seeeval: true}; debugRecordsByDebugId[currentDebugId] = record; } -function reportEnter(method, debugId, length, coordId, elem, args){ +function reportEnter(method, debugId, length, coordId, elem, args) { stuckComplexity.calls += 1; var record = debugRecordsByDebugId[debugId]; record.animated = false; } - -function reportAppear(method, debugId, length, coordId, elem, args){ - +function reportAppear(method, debugId, length, coordId, elem, args) { if (!programChanged) { var record = debugRecordsByDebugId[debugId]; if (record) { @@ -384,7 +378,7 @@ function reportAppear(method, debugId, length, coordId, elem, args){ var index = record.eventIndex; var line = traceEvents[index].location.first_line; var appear_location = traceEvents[index].location; - var tracedIndex = -1; + var tracedIndex = -1; // trace lines that are not animation. while (currentRecordID < debugId) { @@ -419,13 +413,13 @@ function reportAppear(method, debugId, length, coordId, elem, args){ untraceLine(tracedIndex); tracedIndex = -1; } - if (line < prevLine && index == prevIndex + 1){ + if (line < prevLine && index == prevIndex + 1) { update_arrows(prevIndex, index); } traceLine(index); currentRecordID = debugId; record.startCoords[coordId] = collectCoords(elem); - if (debugMode){ + if (debugMode) { showVariables(debugId); } } @@ -433,37 +427,37 @@ function reportAppear(method, debugId, length, coordId, elem, args){ } } -function reportResolve(method, debugId, length, coordId, elem, args){ +function reportResolve(method, debugId, length, coordId, elem, args) { var record = debugRecordsByDebugId[debugId]; if (record) { - if (!record.seeeval){ + if (!record.seeeval) { view.arrow(view.paneid('left'), arrows, -1, false); record.method = method; record.animated = true; var index = record.eventIndex; var line = traceEvents[index].location.first_line - if (index > 0){ + if (index > 0) { var prevLine = traceEvents[index -1].location.first_line; } else{ var prevLine = -1; } record.endCoords[coordId] = collectCoords(elem); untraceLine(index); - } + } } } -function end_program(){ +function end_program() { //goes back and traces unanimated lines at the end of programs. - var currentLine = -1; + var currentLine = -1; var tracedIndex = -1; var justEnded = (currentRecordID <= currentDebugId); var prevLine = -1; - if (traceEvents[prevIndex]){ - prevLine = traceEvents[prevIndex].location.first_line; - } - while (currentRecordID <= currentDebugId){ + if (traceEvents[prevIndex]) { + prevLine = traceEvents[prevIndex].location.first_line; + } + while (currentRecordID <= currentDebugId) { var currentRecord = debugRecordsByDebugId[currentRecordID]; var currentIndex = currentRecord.eventIndex; @@ -478,7 +472,7 @@ function end_program(){ var prevLine = -1; } - if (tracedIndex != -1){ + if (tracedIndex != -1) { untraceLine(tracedIndex); tracedIndex = -1; } @@ -491,7 +485,7 @@ function end_program(){ prevIndex = currentIndex; currentRecordID += 1; } - if (tracedIndex != -1){ + if (tracedIndex != -1) { untraceLine(tracedIndex); view.arrow(view.paneid('left'), arrows, -1, false); tracedIndex = -1; @@ -574,7 +568,7 @@ function traceLine(lineIndex) { var prevLine = -1; var block_mode = view.getPaneEditorBlockMode(view.paneid("left")); - if (traceEvents[lineIndex-1]){ + if (traceEvents[lineIndex-1]) { prevLine = traceEvents[lineIndex-1].location.first_line; } if (debugMode) { @@ -596,11 +590,11 @@ function untraceLine(lineIndex) { var prevLine = -1; var block_mode = view.getPaneEditorBlockMode(view.paneid("left")); - if (traceEvents[lineIndex-1]){ + if (traceEvents[lineIndex-1]) { prevLine = traceEvents[lineIndex-1].location.first_line; } view.clearPaneEditorLine(view.paneid('left'), line, 'debugtrace'); - if (!block_mode){ + if (!block_mode) { view.clearPaneEditorLine(view.paneid('left'), prevLine, 'debugtraceprev'); } } @@ -711,7 +705,7 @@ view.on('parseerror', function(pane, err) { var line = err.loc.line + 1; view.markPaneEditorLine(pane, line, 'debugerror'); } - if (err.message){ + if (err.message) { showDebugMessage( "

Oops, the computer could not show blocks." + "

It says:" + err.message.replace(/^.*Error:/i, '')); @@ -728,7 +722,7 @@ view.on('parseerror', function(pane, err) { var line = err.loc.line + 1; view.markPaneEditorLine(pane, line, 'debugerror'); } - if (err.message){ + if (err.message) { showDebugMessage( "

Oops, the computer could not show blocks." + "

It says:" + err.message.replace(/^.*Error:/i, '')); @@ -741,7 +735,7 @@ view.on('parseerror', function(pane, err) { ////////////////////////////////////////////////////////////////////// view.on('entergutter', function(pane, lineno) { if (pane != view.paneid('left')) return; - if (debugRecordsByLineNo[lineno]){ + if (debugRecordsByLineNo[lineno]) { var debugId = debugRecordsByLineNo[lineno] var eventIndex = debugRecordsByDebugId[debugId].eventIndex; if (debugMode) { @@ -775,7 +769,7 @@ view.on('icehover', function(pane, ev) { var debugId = debugRecordsByLineNo[lineno]; displayProtractorForRecord(debugRecordsByDebugId[debugId]); var eventIndex = debugRecordsByDebugId[debugId].eventIndex; - if (debugMode){ + if (debugMode) { view.arrow(view.paneid('left'), arrows, eventIndex, true); } } @@ -917,7 +911,7 @@ view.on('stop', function() { stopPollingWindow(); }); -view.on('delta', function(){ +view.on('delta', function() { $(".arrow").remove(); view.removeVariables(); programChanged = true; @@ -943,7 +937,7 @@ $('.panetitle').on('click', '.debugtoggle', function () { // respond to manual clicks within the slider function sliderResponse (event, ui) { - slidercurrLine = ui.value; + slidercurrLine = ui.value; sliderToggle(); } diff --git a/content/src/editor.less b/content/src/editor.less index 30a5e93e..bb434119 100644 --- a/content/src/editor.less +++ b/content/src/editor.less @@ -21,6 +21,7 @@ .debugtoggle:hover { color: #fff; } + #backButton { float: left; margin-left: 100px; @@ -36,10 +37,10 @@ } #label { - text-align: center; - font-family: Lato,Verdana,Helvetica,sans-serif; - vertical-align: middle; - font-size: 80%; + text-align: center; + font-family: Lato,Verdana,Helvetica,sans-serif; + vertical-align: middle; + font-size: 80%; } body { @@ -701,8 +702,8 @@ body, .panetitle, #owner { .debugtraceprev{ position: absolute; background: #A1D0FF; - opacity: 1; - transition: opacity 0.2s; + opacity: 1; + transition: opacity 0.2s; } @@ -752,6 +753,7 @@ body#pencildoc #diigolet-csm { .ui-slider-label { color: black } + .blockmenu { position: absolute; top: -28px; @@ -1087,6 +1089,7 @@ body#pencildoc #diigolet-csm { .hpanel:nth-of-type(1) { border-top: none } + .hoverlay { cursor: row-resize; position: fixed; @@ -1097,8 +1100,8 @@ body#pencildoc #diigolet-csm { z-index: 999999 } -.arrow { - pointer-events:none; +.arrow { + pointer-events:none; } .editor .vars { @@ -1174,53 +1177,53 @@ body#pencildoc #diigolet-csm { visibility: visible; opacity: 1; top: -30px; -} +} #slider.ui-slider .ui-slider-handle { top: -6px; height: 15px; width: 15px; - transform: rotateZ(360deg); + transform: rotateZ(360deg); z-index: 400; } #slider.ui-slider .ui-slider-handle.ui-state-hover, #slider.ui-slider .ui-slider-handle.ui-state-focus, #slider.ui-slider .ui-slider-handle.ui-state-active { - border-color: #172f38; -} - + border-color: #172f38; +} #slider.ui-slider .ui-slider-pip .ui-slider-line { background: #d5cebc; - transition: all 0.4s ease; + transition: all 0.4s ease; } #slider.ui-slider.ui-slider-horizontal { - height: 6px; + height: 6px; } #slider.ui-slider.ui-slider-horizontal .ui-slider-pip { - top: 10px; + top: 10px; } #slider.ui-slider.ui-slider-horizontal .ui-slider-pip .ui-slider-line { width: 2px; height: 5px; - margin-left: -1px; + margin-left: -1px; } #slider.ui-slider.ui-slider-horizontal .ui-slider-pip[class*=ui-slider-pip-selected] .ui-slider-line { - height: 10px; + height: 10px; } #slider.ui-slider.ui-slider-horizontal .ui-slider-pip.ui-slider-pip-inrange .ui-slider-line { - height: 5px; + height: 5px; } #slider.ui-slider-horizontal .ui-slider-range-min { - background: #1E90FF; -} + background: #1E90FF; +} + .texttoggle, .blocktoggle { position: absolute; width: 32px; From 03b923667ef62fe57c3614e73f03a9aa1eeee878 Mon Sep 17 00:00:00 2001 From: Jeremy Ruten Date: Thu, 20 Aug 2015 21:33:49 -0600 Subject: [PATCH 197/199] Update pencil-tracer.js --- content/lib/pencil-tracer.js | 105 +++++++++++++++++------------------ content/src/controller.js | 4 +- 2 files changed, 52 insertions(+), 57 deletions(-) diff --git a/content/lib/pencil-tracer.js b/content/lib/pencil-tracer.js index 9a90e43b..735627f7 100644 --- a/content/lib/pencil-tracer.js +++ b/content/lib/pencil-tracer.js @@ -287,7 +287,7 @@ }).call(this)).join(", "); }; - CoffeeScriptInstrumenter.prototype.findFunctionCalls = function(node, parent, grandparent, vars) { + CoffeeScriptInstrumenter.prototype.findFunctionCalls = function(node, parent, grandparent, funcs) { var j, lastProp, len, name, prop, ref, soak; if (parent == null) { parent = null; @@ -295,8 +295,8 @@ if (grandparent == null) { grandparent = null; } - if (vars == null) { - vars = []; + if (funcs == null) { + funcs = []; } if (node instanceof this.nodeTypes.Call && !(grandparent instanceof this.nodeTypes.Op && grandparent.operator === "new")) { soak = node.soak; @@ -322,7 +322,7 @@ } } node.pencilTracerReturnVar = this.temporaryVariable("returnVar"); - vars.push({ + funcs.push({ name: name, tempVar: node.pencilTracerReturnVar, argsString: this.argsToString(node.args) @@ -336,11 +336,11 @@ skip || (skip = child instanceof _this.nodeTypes.Code); skip || (skip = !_this.shouldInstrumentNode(child)); if (!skip) { - return _this.findFunctionCalls(child, node, parent, vars); + return _this.findFunctionCalls(child, node, parent, funcs); } }; })(this)); - return vars; + return funcs; }; CoffeeScriptInstrumenter.prototype.nodeIsObj = function(node) { @@ -356,7 +356,7 @@ }; CoffeeScriptInstrumenter.prototype.shouldInstrumentNode = function(node) { - return !node.pencilTracerInstrumented && !(node instanceof this.nodeTypes.IcedRuntime) && (!(node instanceof this.nodeTypes.IcedTailCall) || node.value instanceof this.nodeTypes.Value) && !(node instanceof this.nodeTypes.Comment) && !(node instanceof this.nodeTypes.For) && !(node instanceof this.nodeTypes.While) && !(node instanceof this.nodeTypes.Switch) && !(node instanceof this.nodeTypes.If) && !(node instanceof this.nodeTypes.Class) && !(node instanceof this.nodeTypes.Try) && !(node instanceof this.nodeTypes.Await); + return !this.shouldSkipNode(node) && (!(node instanceof this.nodeTypes.IcedTailCall) || node.value instanceof this.nodeTypes.Value) && !(node instanceof this.nodeTypes.Comment) && !(node instanceof this.nodeTypes.For) && !(node instanceof this.nodeTypes.While) && !(node instanceof this.nodeTypes.Switch) && !(node instanceof this.nodeTypes.If) && !(node instanceof this.nodeTypes.Class) && !(node instanceof this.nodeTypes.Try) && !(node instanceof this.nodeTypes.Await); }; CoffeeScriptInstrumenter.prototype.mapChildrenArray = function(children, func) { @@ -668,7 +668,7 @@ } }; - CoffeeScriptInstrumenter.prototype.instrument = function(filename, code) { + CoffeeScriptInstrumenter.prototype.instrument = function(code) { var ast, csOptions, result, token; csOptions = { runtime: "inline", @@ -704,13 +704,13 @@ })(); - exports.instrumentCoffee = function(filename, code, coffee, options) { + exports.instrumentCoffee = function(code, coffee, options) { var instrumenter; if (options == null) { options = {}; } instrumenter = new CoffeeScriptInstrumenter(coffee, options); - return instrumenter.instrument(filename, code); + return instrumenter.instrument(code); }; }).call(this); @@ -871,7 +871,7 @@ })()) + "]"; } } - eventObj = "{location: " + locationObj + ", type: '" + eventType + "', " + extra + "}"; + eventObj = "{ location: " + locationObj + ", type: '" + eventType + "', " + extra + " }"; instrumentedNode = acorn.parse(this.options.traceFunc + "(" + eventObj + ");").body[0]; instrumentedNode.pencilTracerInstrumented = true; instrumentedNode.expression.pencilTracerInstrumented = true; @@ -967,36 +967,35 @@ } } } - for (key in node) { - if (foundEndOfMemberExpression) { - continue; - } - if (node.type === "Property" && key === "key") { - continue; - } - if (((ref3 = node.type) === "FunctionExpression" || ref3 === "FunctionDeclaration") && key === "params") { - continue; - } - if (node.type === "MemberExpression" && key === "property" && !node.computed) { - continue; - } - if (node.type === "MemberExpression" && key === "object" && ((ref4 = node[key].type) === "Identifier" || ref4 === "ThisExpression") && !node.computed) { - continue; - } - if (((ref5 = node.type) === "CallExpression" || ref5 === "NewExpression") && key === "callee" && ((ref6 = node[key].type) === "ThisExpression" || ref6 === "Identifier")) { - continue; - } - if (isArray(node[key])) { - ref7 = node[key]; - for (j = 0, len = ref7.length; j < len; j++) { - child = ref7[j]; - if (ref8 = child.type, indexOf.call(FIND_VARIABLES_IN, ref8) >= 0) { - this.findVariables(child, node, vars); - } + if (!foundEndOfMemberExpression) { + for (key in node) { + if (node.type === "Property" && key === "key") { + continue; } - } else if (node[key] && typeof node[key].type === "string") { - if (ref9 = node[key].type, indexOf.call(FIND_VARIABLES_IN, ref9) >= 0) { - this.findVariables(node[key], node, vars); + if (((ref3 = node.type) === "FunctionExpression" || ref3 === "FunctionDeclaration") && key === "params") { + continue; + } + if (node.type === "MemberExpression" && key === "property" && !node.computed) { + continue; + } + if (node.type === "MemberExpression" && key === "object" && ((ref4 = node[key].type) === "Identifier" || ref4 === "ThisExpression") && !node.computed) { + continue; + } + if (((ref5 = node.type) === "CallExpression" || ref5 === "NewExpression") && key === "callee" && ((ref6 = node[key].type) === "ThisExpression" || ref6 === "Identifier")) { + continue; + } + if (isArray(node[key])) { + ref7 = node[key]; + for (j = 0, len = ref7.length; j < len; j++) { + child = ref7[j]; + if (ref8 = child.type, indexOf.call(FIND_VARIABLES_IN, ref8) >= 0) { + this.findVariables(child, node, vars); + } + } + } else if (node[key] && typeof node[key].type === "string") { + if (ref9 = node[key].type, indexOf.call(FIND_VARIABLES_IN, ref9) >= 0) { + this.findVariables(node[key], node, vars); + } } } } @@ -1036,14 +1035,14 @@ }).call(this)).join(", "); }; - JavaScriptInstrumenter.prototype.findFunctionCalls = function(node, vars) { + JavaScriptInstrumenter.prototype.findFunctionCalls = function(node, funcs) { var child, j, key, len, name, ref, ref1, ref2; - if (vars == null) { - vars = []; + if (funcs == null) { + funcs = []; } if (node.pencilTracerReturnVar) { name = node.callee.type === "ThisExpression" ? "this" : node.callee.type === "Identifier" ? node.callee.name : node.callee.type === "MemberExpression" && !node.callee.computed ? node.callee.property.name : ""; - vars.push({ + funcs.push({ name: name, tempVar: node.pencilTracerReturnVar, argsString: this.argsToString(node["arguments"]) @@ -1055,16 +1054,16 @@ for (j = 0, len = ref.length; j < len; j++) { child = ref[j]; if (ref1 = child.type, indexOf.call(FIND_VARIABLES_IN, ref1) >= 0) { - this.findFunctionCalls(child, vars); + this.findFunctionCalls(child, funcs); } } } else if (node[key] && typeof node[key].type === "string") { if (ref2 = node[key].type, indexOf.call(FIND_VARIABLES_IN, ref2) >= 0) { - this.findFunctionCalls(node[key], vars); + this.findFunctionCalls(node[key], funcs); } } } - return vars; + return funcs; }; JavaScriptInstrumenter.prototype.shouldInstrumentWithBlock = function(node, parent) { @@ -1223,7 +1222,7 @@ })(this)); }; - JavaScriptInstrumenter.prototype.instrument = function(filename, code) { + JavaScriptInstrumenter.prototype.instrument = function(code) { var ast, name, result, tempVarsDeclaration; this.lines = code.match(/^.*((\r\n|\n|\r)|$)/gm); this.lines.unshift(null); @@ -1231,7 +1230,6 @@ this.referencedVars = []; ast = acorn.parse(code, { locations: true, - sourceFile: filename, onToken: (function(_this) { return function(token) { if (token.type.label === "name" && _this.referencedVars.indexOf(token.value) === -1) { @@ -1270,11 +1268,8 @@ return ast; } if (this.options.sourceMap) { - if (typeof filename !== "string" || filename.length === 0) { - filename = "untitled.js"; - } result = escodegen.generate(ast, { - sourceMap: filename, + sourceMap: "untitled.js", sourceMapWithCode: true }); result.map = result.map.toString(); @@ -1288,13 +1283,13 @@ })(); - exports.instrumentJs = function(filename, code, options) { + exports.instrumentJs = function(code, options) { var instrumenter; if (options == null) { options = {}; } instrumenter = new JavaScriptInstrumenter(options); - return instrumenter.instrument(filename, code); + return instrumenter.instrument(code); }; }).call(this); diff --git a/content/src/controller.js b/content/src/controller.js index 7442502d..ba4a3798 100644 --- a/content/src/controller.js +++ b/content/src/controller.js @@ -1862,7 +1862,7 @@ function instrumentCode(code, language) { includeArgsStrings: true, sourceMap: true }; - result = pencilTracer.instrumentJs('', code, options); + result = pencilTracer.instrumentJs(code, options); debug.setSourceMap(result.map); code = result.code; } else if (language === 'coffeescript') { @@ -1872,7 +1872,7 @@ function instrumentCode(code, language) { sourceMap: true, bare: true }; - result = pencilTracer.instrumentCoffee('', code, icedCoffeeScript, options); + result = pencilTracer.instrumentCoffee(code, icedCoffeeScript, options); debug.setSourceMap(result.map); code = result.code; } From c951e41982a48630a0d47f48b9ae490804b5a691 Mon Sep 17 00:00:00 2001 From: Jeremy Ruten Date: Thu, 20 Aug 2015 23:00:58 -0600 Subject: [PATCH 198/199] Add some comments to explain variable/function tracking --- content/src/controller.js | 41 +++++++++++++---------- content/src/debug.js | 70 ++++++++++++++++++++++++++++++++++++--- content/src/filetype.js | 1 + content/src/view.js | 21 +++++++++++- 4 files changed, 111 insertions(+), 22 deletions(-) diff --git a/content/src/controller.js b/content/src/controller.js index ba4a3798..519e8f72 100644 --- a/content/src/controller.js +++ b/content/src/controller.js @@ -1853,29 +1853,37 @@ function cancelAndClearPosition(pos) { modelatpos(pos).running = false; } +// Takes a JavaScript or CoffeeScript program, instruments it, and returns the +// result as JavaScript. `language` can be either 'javascript' or +// 'coffeescript'. +// +// Returns false if the input program couldn't be parsed. function instrumentCode(code, language) { try { - var result, options; + // Options for pencil-tracer. + var options = { + traceFunc: 'ide.trace', // ide.trace() in debug.js will collect trace events. + includeArgsStrings: true, + sourceMap: true + }; + + var result; if (language === 'javascript') { - options = { - traceFunc: 'ide.trace', - includeArgsStrings: true, - sourceMap: true - }; result = pencilTracer.instrumentJs(code, options); - debug.setSourceMap(result.map); - code = result.code; } else if (language === 'coffeescript') { - options = { - traceFunc: 'ide.trace', - includeArgsStrings: true, - sourceMap: true, - bare: true - }; + options.bare = true; result = pencilTracer.instrumentCoffee(code, icedCoffeeScript, options); - debug.setSourceMap(result.map); - code = result.code; + } else { + // Return original code if we've been passed an unexpected language. + return code; } + + // Pass the source map to the debugger so it can show line numbers of + // errors properly. + debug.setSourceMap(result.map); + + // Return the instrumented code. + return result.code; } catch (err) { // An error here means that either the user's code has a syntax error, or // pencil-tracer has a bug. Returning false here means the user's code @@ -1884,7 +1892,6 @@ function instrumentCode(code, language) { // their code will still run but with the debugger disabled. return false; } - return code; } function runCodeAtPosition(position, doc, filename, emptyOnly) { diff --git a/content/src/debug.js b/content/src/debug.js index a3724e37..c827be2c 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -219,6 +219,10 @@ function detectStuckProgram() { // VARIABLE & FUNCTION CALL TRACKING ////////////////////////////////////////////////////////////////////// +// jquery-turtle functions that are used very commonly in users' programs, and +// return either a useless result (like undefined) or a complex result (like +// a jquery object) just clutter up the variable/function annotations. So we +// ignore these type of functions when doing function call tracking. var untrackedFunctions = [ "fd", "bk", "rt", "lt", "slide", "jump", "moveto", "jumpto", "turnto", "play", "home", "pen", "pu", "pd", "pe", "fill", "dot", "label", "speed", "ht", "st", @@ -227,6 +231,28 @@ var untrackedFunctions = [ "readstr", "button", "table", "send", "recv" ]; +// Adds each variable snapshot in `vars` to `variables`, which keeps track of +// the history of each variable. +// +// Each object in the `variables` array has a `name` property and a `history` +// property. The `history` property contains an array of objects, each object +// representing a snapshot of the variable's value at a certain point in time +// during the program's execution. Each snapshot consists of the line number +// the variable appears on, the debug id, and the variable's value as a string. +// Here's an example of what the `variables` array might look like: +// +// [ +// { name: 'x', +// history: [{debugId: 0, lineNum: 1, value: 'undefined'}, +// {debugId: 1, lineNum: 1, value: '1'}]}, +// { name: 'y', +// history: [{debugId: 2, lineNum: 2, value: 'undefined'}, +// {debugId: 3, lineNum: 2, value: '2'}]} +// ] +// +// When we want to display these variables at a certain step (debug id) in the +// program, we'll go through each variable and find the most recent snapshot of +// its value that is no later than that step. function updateVariables(lineNum, debugId, vars) { for (var i = 0; i < vars.length; i++) { // Filter out function definitions. @@ -235,21 +261,29 @@ function updateVariables(lineNum, debugId, vars) { // Filter out predefined global variables. if (untrackedVariables.indexOf(vars[i].name) !== -1) continue; - var varRecord = null; + // Convert the variable's value to a string. var value = valueToString(vars[i].value); + + // Find the object in `variables` for this variable, if one exists. + var varRecord = null; for (var j = 0; j < variables.length; j++) { if (vars[i].name === variables[j].name) { varRecord = variables[j]; break; } } + if (varRecord === null) { + // If this is the first time we've seen this variable, make an object for + // it and append it to `variables`. varRecord = { name: vars[i].name, history: [{debugId: debugId, lineNum: lineNum, value: value}] }; variables.push(varRecord); } else { + // Otherwise, push the value of the variable, along with the current + // line number and debug id, to the variable's history array. var last = varRecord.history[varRecord.history.length - 1]; if (last.value !== value) { varRecord.history.push({debugId: debugId, lineNum: lineNum, value: value}); @@ -258,20 +292,36 @@ function updateVariables(lineNum, debugId, vars) { } } +// Adds each function call in `funcs` to `functionCalls`, which keeps track of +// the return value of each function call. Function calls are tracked in the +// exact same way as variables, see the explanation of updateVariables() above. function updateFunctionCalls(lineNum, debugId, funcs) { for (var i = 0; i < funcs.length; i++) { // Filter out common turtle functions. if (untrackedFunctions.indexOf(funcs[i].name) !== -1) continue; - var funcRecord = null; + // Convert the function's return value to a string. var value = valueToString(funcs[i].value); + + // Find the object in `functionCalls` for this function call, if one exists. + var funcRecord = null; for (var j = 0; j < functionCalls.length; j++) { - if (funcs[i].name === functionCalls[j].name && funcs[i].argsString === functionCalls[j].argsString && lineNum === functionCalls[j].lineNum) { + // Function calls that have the same name, take the same string of + // arguments, and appear on the same line are assumed to be the same, for + // the purposes of displaying their value. + var sameFunction = + (funcs[i].name === functionCalls[j].name) && + (funcs[i].argsString === functionCalls[j].argsString) && + (lineNum === functionCalls[j].lineNum); + if (sameFunction) { funcRecord = functionCalls[j]; break; } } + if (funcRecord === null) { + // If this is the first time we've seen this function call, make an + // object for it and append it to `functionCalls`. funcRecord = { name: funcs[i].name, argsString: funcs[i].argsString, @@ -280,14 +330,21 @@ function updateFunctionCalls(lineNum, debugId, funcs) { }; functionCalls.push(funcRecord); } else { + // Otherwise, push the return value, along with the debug id, to the + // function call's history array. var last = funcRecord.history[funcRecord.history.length - 1]; if (last.value !== value) { - funcRecord.history.push({debugId: debugId, lineNum: lineNum, value: value}); + funcRecord.history.push({debugId: debugId, value: value}); } } } } +// Convert a variable's value or function call's return value to a string that +// will be displayed to the user. +// +// For now, functions and objects are displayed as "" and "", +// and any other values are converted to a string using util.inspect(). function valueToString(value) { if (typeof value === 'function') { return ''; @@ -298,9 +355,13 @@ function valueToString(value) { } } +// Redraw all variable annotations for the given debug id (i.e. step in the +// program's execution). function showVariables(debugId) { + // Empty out the annotation divs for each line, but keep the divs. view.emptyVariables(); + // Show each tracked variable that existed at this step in the program. for (var i = 0; i < variables.length; i++) { var historyEntry = null; for (var j = variables[i].history.length - 1; j >= 0; j--) { @@ -314,6 +375,7 @@ function showVariables(debugId) { } } + // Show each tracked function call that existed at this step in the program. for (var i = 0; i < functionCalls.length; i++) { var historyEntry = null; for (var j = functionCalls[i].history.length - 1; j >= 0; j--) { diff --git a/content/src/filetype.js b/content/src/filetype.js index 938b2a0d..04d3bb4f 100644 --- a/content/src/filetype.js +++ b/content/src/filetype.js @@ -184,6 +184,7 @@ function wrapTurtle(doc, domain, pragmasOnly, setupScript, instrumenter) { // Instruments the code for debugging, always producing javascript. var newText = instrumenter(text, originalLanguage); if (newText !== false) { + // Proceed with the instrumented code if there wasn't a syntax error. text = newText; maintype = 'text/javascript'; instrumented = true; diff --git a/content/src/view.js b/content/src/view.js index 0c00eb97..22a6cd67 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -3428,7 +3428,13 @@ function coords_and_offsets(firstLoc, secondLoc, show_fade, block_mode, pane, dr } } +// Shows a single variable or function call annotation at a particular line +// number. If annotations already exist at that line number, the annotation is +// appended to them. function showVar(pane, lineNum, name, value, argsString) { + // Create the annotation string that will be displayed to the user. Variable + // annotations will look like "x=3", and function call annotations will look + // like "f(x, y)=3". var text = htmlEscape(name); if (typeof argsString === "string") { text += "(" + htmlEscape(argsString) + ")"; @@ -3437,8 +3443,13 @@ function showVar(pane, lineNum, name, value, argsString) { var divId = "line" + lineNum + "vars"; if ($("#" + divId).length) { + // If the annotation div for this line number already exists, append the + // new annotation to it. $("#" + divId).append(text); } else { + // Otherwise we have to create an annotation div. First, calculate the + // position the div needs to align with its line number. Droplet and Ace + // Editor have different APIs for this. var coords; var offsetTop = 0; var blockMode = getPaneEditorBlockMode(pane); @@ -3452,16 +3463,19 @@ function showVar(pane, lineNum, name, value, argsString) { offsetTop = $("div[id^='editor_']").offset().top; } + // Create the div and position it. var div = document.createElement('div'); div.id = divId; div.className = "vars"; div.innerHTML = text; - div.style.visibility = 'visible'; + div.style.visibility = "visible"; div.style.position = "absolute"; div.style.zIndex = "10"; div.style.right = "25px"; div.style.top = String(coords.pageY - offsetTop) + "px"; + // Append it to the proper element, depending on whether we're in block + // mode or not. if (blockMode) { $("div[id^='editor_'] .droplet-main-scroller").append(div); } else { @@ -3470,14 +3484,19 @@ function showVar(pane, lineNum, name, value, argsString) { } } +// Clears all the annotation divs, but leaves the divs themselves so we don't +// have to do all the work of positioning them again. function emptyVariables() { $(".vars").empty(); } +// Removes all the annotation divs. function removeVariables() { $(".vars").remove(); } +// Repositions each annotation div. This needs to happen when the user scrolls +// in Ace Editor mode. function repositionVariables(pane) { $("#" + pane + " .vars").each(function() { var matches = this.id.match(/^line(\d+)vars$/); From bff2831f6a7da7077d0901f33dd5575a4629ef02 Mon Sep 17 00:00:00 2001 From: Jeremy Ruten Date: Thu, 20 Aug 2015 23:01:57 -0600 Subject: [PATCH 199/199] Fix variable tracking for JavaScript programs that use global variables. --- content/src/showturtle.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/content/src/showturtle.js b/content/src/showturtle.js index ace7d6eb..30e5ad32 100644 --- a/content/src/showturtle.js +++ b/content/src/showturtle.js @@ -17,10 +17,11 @@ } } $.turtle(map); + var untrackedVars = Object.keys(ww); ww._start_ide_ = function(pump) { if (ww.see) ww.see.init(pump); if (ww.ide && ww.ide.reportEvent) ww.ide.reportEvent('init'); - if (ww.ide && ww.ide.setUntrackedVars) ww.ide.setUntrackedVars(Object.keys(ww)); + if (ww.ide && ww.ide.setUntrackedVars) ww.ide.setUntrackedVars(untrackedVars); delete ww._start_ide_; delete ww._start_ide_cs_; delete ww._start_ide_js_;