@@ -235,7 +235,6 @@ |
} |
}; |
|
- |
var csipOutput, csipGenCode; |
|
/** |
@@ -522,6 +521,10 @@ |
"value": $('#problem_name').val() |
}, |
{ |
+ "name": "public", |
+ "value": document.getElementById('problem_public').checked |
+ }, |
+ { |
"name": "code", |
"value": editor.getSession().getValue() |
}, |
@@ -557,15 +560,9 @@ |
}; |
} |
|
-// run the code |
-function runCode() { |
+function startSpinner(element) { |
"use strict"; |
- |
- console.log('Attempting run...'); |
|
- var variables = getVariables('variables'), |
- request = getCSIPRequest(); |
- |
// start spinner |
var opts = { |
lines: 13, // The number of lines to draw |
@@ -585,9 +582,72 @@ |
top: '50%', // Top position relative to parent |
left: '50%' // Left position relative to parent |
}; |
- var target = document.getElementById('innerModal'); |
+ var target = document.getElementById(element); |
var spinner = new Spinner(opts).spin(target); |
- $(target).data('spinner', spinner); |
+ return spinner; |
+} |
+ |
+// open the problems list dialog |
+function openDialog() { |
+ "use strict"; |
+ |
+ // open the window |
+ window.location.href = '#openModal'; |
+ |
+ // start spinner |
+ var spinner = startSpinner('openModalInner'); |
+ |
+ // get the data to send |
+ var cursor_val = $('#cursor').val(); |
+ var data = { |
+ limit: 20 |
+ }; |
+ if (cursor_val !== '') { |
+ data.cursor = cursor_val; |
+ } |
+ |
+ // get the problems list |
+ $.ajax({ |
+ url: '/problems_list', |
+ type: 'GET', |
+ dataType: 'json', |
+ data: data, |
+ success: function(response) { |
+ |
+ // response.limit, response.cursor, response.more, response.problems |
+ var problemsList = $('#problemsList'); |
+ problemsList.empty(); |
+ |
+ if (typeof response.problems !== 'undefined') { |
+ |
+ if (response.problems.length == 0) { |
+ problemsList.append('<span>No optimization problems saved yet!</span>'); |
+ } else { |
+ response.problems.forEach( function(problem) { |
+ var button = document.createElement('a'); |
+ button.className = "a-button-type padding-10"; |
+ button.setAttribute('href', "/?id=" + problem.id); |
+ button.innerHTML = problem.name; |
+ problemsList.append(button); |
+ }); |
+ } |
+ |
+ } |
+ |
+ spinner.stop(); |
+ } |
+ }); |
+} |
+ |
+// run the code |
+function runCode() { |
+ "use strict"; |
+ |
+ console.log('Attempting run...'); |
+ |
+ var variables = getVariables('variables'), |
+ request = getCSIPRequest(), |
+ spinner = startSpinner('chartModalInner'); |
|
// print request |
console.log('request'); |
@@ -775,7 +835,7 @@ |
}; |
|
// stop the spinner |
- $(target).data('spinner').stop(); |
+ spinner.stop(); |
} |
}); |
} |
@@ -847,3 +907,9 @@ |
link.click(); |
|
} |
+ |
+// save code on Ctrl+s |
+shortcut.add("Ctrl+S", function() { |
+ saveCode(); |
+}); |
+ |
@@ -5,7 +5,7 @@ |
from templates import env |
from runner import RunHandler |
from accounts import AccountHandler |
-from problems import ProblemHandler, ProblemIDHandler, ProblemListHandler, ProblemTemplateHandler |
+from problems import ProblemHandler, ProblemIDHandler, ProblemListHandler |
|
|
class MainHandler(webapp2.RequestHandler): |
@@ -41,6 +41,5 @@ |
('/run', RunHandler), |
('/problem', ProblemHandler), |
('/problems_list', ProblemListHandler), |
- ('/problems_template', ProblemTemplateHandler), |
- ('/problems_id', ProblemIDHandler), |
+ ('/problem_id', ProblemIDHandler), |
], debug=True) |
@@ -100,8 +100,8 @@ |
variables = ndb.StructuredProperty(Variable, repeated=True) |
|
# dates |
- date_created = ndb.DateProperty(auto_now_add=True) |
- date_modified = ndb.DateProperty(auto_now=True) |
+ date_created = ndb.DateTimeProperty(auto_now_add=True) |
+ date_modified = ndb.DateTimeProperty(auto_now=True) |
|
def build_key(self): |
return Problem.build_key_from_name(self.name, self.owner_id) |
@@ -167,9 +167,12 @@ |
|
return json.dumps(self.csip_dict()) |
|
+ def exists(self): |
+ return len(self.query(ancestor=self.key).fetch(1)) != 0 |
+ |
@staticmethod |
def build_key_from_name(name, owner_id): |
- return ndb.Key(Problem, name, parent=Account.key_from_id(owner_id)) |
+ return ndb.Key('Problem', name, parent=Account.key_from_id(owner_id)) |
|
@staticmethod |
def from_json(j_str, owner_id=None, member_ids=None): |
@@ -180,11 +183,19 @@ |
@staticmethod |
def from_dict(d, owner_id=None, member_ids=None): |
|
- # algorithm parameters |
- p = Problem() |
+ # check existence of problem in datastore |
params = d["parameter"] |
+ name = get_param(params, 'name') |
+ if owner_id is not None and Problem.exists_by_name(name, owner_id): |
+ p = Problem.retrieve_by_name(name, owner_id) |
+ else: |
+ p = Problem() |
+ p.name = name |
+ if owner_id is not None: |
+ p.owner_id = owner_id |
+ p.set_key() |
+ |
p.is_public = get_param(params, 'is_public', False) |
- p.name = get_param(params, 'name') |
p.method = get_param(params, 'method') |
p.max_evals = get_param(params, 'max_evals') |
p.population = get_param(params, 'population') |
@@ -199,9 +210,6 @@ |
# set |
if member_ids is not None: |
p.member_ids = member_ids |
- if owner_id is not None: |
- p.owner_id = owner_id |
- p.set_key() |
|
# return the session |
return p |
@@ -2,8 +2,8 @@ |
import webapp2 |
from templates import env |
from models import Problem |
-from google.appengine.ext import ndb |
from google.appengine.api import users |
+from google.appengine.datastore.datastore_query import Cursor |
|
|
class ProblemHandler(webapp2.RequestHandler): |
@@ -73,14 +73,30 @@ |
|
def get(self): |
|
- limit = self.request.get('limit', 10) |
- page = self.request.get('page', 1) |
- self.response.write({'limit': limit, 'page': page}) |
+ user = users.get_current_user() |
+ if user: |
|
+ limit = int(self.request.get('limit', 20)) |
+ cursor = self.request.get('cursor') |
|
-class ProblemTemplateHandler(webapp2.RequestHandler): |
+ q = Problem.query(Problem.owner_id == user.user_id()).order(-Problem.date_modified) |
+ if cursor: |
+ problems, next_cursor, more = q.fetch_page(limit, start_cursor=Cursor(urlsafe=cursor)) |
+ else: |
+ problems, next_cursor, more = q.fetch_page(limit) |
+ self.response.write(json.dumps({ |
+ 'limit': limit, |
+ 'cursor': next_cursor.urlsafe(), |
+ 'more': more, |
+ 'problems': [{ |
+ 'name': p.name, |
+ 'id': p.key.urlsafe(), |
+ 'date_modified': str(p.date_modified) |
+ } for p in problems] |
+ })) |
|
- def get(self): |
+ else: |
|
- problem_page = env.get_template('problems.html').render() |
- self.response.write(problem_page) |
+ self.error(403) |
+ |
+ |
@@ -109,7 +109,7 @@ |
|
.problem-row { |
display: inherit; |
- margin: 0px auto; |
+ margin: 0 auto; |
width: 100%; |
min-height: 36px; |
} |
@@ -155,23 +155,53 @@ |
.flex-container { |
display: -webkit-flex; |
display: flex; |
- flex-wrap: wrap; |
-webkit-flex-direction: row; |
+ -moz-flex-direction: row; |
+ -ms-flex-direction: row; |
flex-direction: row; |
} |
|
-.flex-container-center { |
+.flex-container-v { |
display: -webkit-flex; |
+ display: -ms-flexbox; |
display: flex; |
- flex-wrap: wrap; |
- -webkit-flex-direction: row; |
- flex-direction: row; |
+ -webkit-flex-direction: column; |
+ -moz-flex-direction: column; |
+ -ms-flex-direction: column; |
+ flex-direction: column; |
+ height: 100%; |
+} |
+ |
+.flex-center { |
-webkit-align-items: center; |
+ -moz-align-items: center; |
+ -ms-align-items: center; |
align-items: center; |
-webkit-justify-content: center; |
+ -moz-justify-content: center; |
+ -ms-justify-content: center; |
justify-content: center; |
} |
|
+.flex-wrap { |
+ -webkit-flex-wrap: wrap; |
+ flex-wrap: wrap; |
+} |
+ |
+.flex-fixed { |
+ -webkit-flex: 0 0 auto; |
+ -moz-flex: 0 0 auto; |
+ -ms-flex: 0 0 auto; |
+ flex: 0 0 auto; |
+} |
+ |
+.flex-fill-v { |
+ -webkit-flex: 0 1 auto; |
+ -moz-flex: 0 1 auto; |
+ -ms-flex: 0 1 auto; |
+ flex: 0 1 auto; |
+} |
+ |
.param-row { |
display: inherit; |
-webkit-flex-direction: inherit; |
@@ -233,14 +263,6 @@ |
display: inherit; |
} |
|
-.auto-margin { |
- margin: 0 auto; |
-} |
- |
-.margin-top { |
- margin-top: 10px; |
-} |
- |
/* |
* BUTTON TYPES |
*/ |
@@ -334,7 +356,47 @@ |
background-size: 29px; |
} |
|
+.link-button { |
+ background: #000000 url("/images/link_white.png") no-repeat center; |
+ background-size: 25px; |
+} |
+ |
.open-button { |
background: #000000 url("/images/open_white.png") no-repeat center; |
background-size: 29px; |
+} |
+ |
+/* |
+ * MISC |
+ */ |
+.totally-hidden { |
+ display: none; |
+} |
+ |
+.padding-10 { |
+ padding: 10px 10px; |
+} |
+ |
+.padding-50 { |
+ padding: 50px 50px; |
+} |
+ |
+.margin-10 { |
+ margin: 10px 10px; |
+} |
+ |
+.margin-50 { |
+ margin: 50px 50px; |
+} |
+ |
+.auto-margin { |
+ margin: 0 auto; |
+} |
+ |
+.margin-top { |
+ margin-top: 10px; |
+} |
+ |
+.fill-height { |
+ max-height: 100%; |
} |
\ No newline at end of file |
@@ -47,8 +47,57 @@ |
/* |
* OPEN MODAL |
*/ |
+.openModal { |
|
+ font-weight: 900; |
+ font-size: large; |
|
+ position: absolute; |
+ top: 0; |
+ right: 0; |
+ bottom: 0; |
+ left: 0; |
+ |
+ background: rgba(0,0,0,0.8); |
+ z-index: 99999; |
+ |
+ opacity:0; |
+ -webkit-transition: opacity 400ms ease-in; |
+ -moz-transition: opacity 400ms ease-in; |
+ transition: opacity 400ms ease-in; |
+ pointer-events: none; |
+ color: whitesmoke; |
+ |
+} |
+ |
+.openModal:target { |
+ opacity:1; |
+ pointer-events: auto; |
+} |
+ |
+.openModal > div { |
+ width: 80%; |
+ height: calc(100% - 100px); |
+ height: -webkit-calc(100% - 100px); |
+ position: relative; |
+ margin: 50px auto; |
+ border-radius: 10px; |
+ |
+ background: #606060; |
+ /*background: -moz-linear-gradient(#606060, #646464);*/ |
+ /*background: -webkit-linear-gradient(#606060, #646464);*/ |
+ /*background: -o-linear-gradient(#606060, #646464);*/ |
+} |
+ |
+.problems-list-container { |
+ margin: 5px 5px; |
+ overflow-y: auto; |
+ height: 100%; |
+} |
+ |
+/* |
+ * OTHER |
+ */ |
.close { |
background: #606061; |
color: #FFFFFF; |
@@ -17,6 +17,7 @@ |
<script type="text/javascript" src="/js/jquery.dataTables.min.js"></script> |
<script type="text/javascript" src="/js/dataTables.tableTools.min.js"></script> |
<script type="text/javascript" src="/js/spin.min.js"></script> |
+ <script type="text/javascript" src="/js/shortcut.js"></script> |
<script type="text/javascript" src="/js/multiobj.js"></script> |
|
</head> |
@@ -34,6 +35,7 @@ |
<div class="flex-container"> |
<div class="param-row"> |
<div> |
+ <button onclick="openDialog();" class="a-button-type open-button" title="Load Optimization Problems"></button> |
<button onclick="runCode();" class="button-type play-button" title="Run Optimization"></button> |
<button id="modal-button" onclick="window.location.href = '#chartModal';" class="button-type chart-button hidden" title="Show Graph or Table"></button> |
<button id="download-button" onclick="downloadOutput();" class="button-type download-button hidden" title="Download Results"></button> |
@@ -41,11 +43,13 @@ |
</div> |
<div class="flex-right"> |
{% if has_user %} |
- <button onclick="openDialog();" class="button-type open-button" title="Open Different Optimization Problems"></button> |
+ {% if problem.key %} |
+ <button onclick="window.prompt('Press Ctrl+C to Copy the link below!', 'http://' + location.host + '/?id={{ problem.key.urlsafe() }}');" class="button-type link-button" title="Get Link to This Optimization Problem!"></button> |
+ {% endif %} |
<button onclick="saveCode();" class="button-type save-button" title="Save this Optimization Problem"></button> |
<a href="{{ user_url }}" class="a-button-type button-padding-extra">Sign Out</a> |
{% else %} |
- <a href="{{ user_url }}" class="a-button-type button-padding-extra" title="Sign in so you can save">Sign In To Save</a> |
+ <a href="{{ user_url }}" class="a-button-type button-padding-extra" title="Sign in so you can save your optimization problems!">Sign In With Google</a> |
{% endif %} |
</div> |
</div> |
@@ -55,13 +59,17 @@ |
<div id="parameters" class="left-panel"> |
<div id="parameter_rows" class="flex-container"> |
|
- <h2 class="param-row margin-top">Problem Name</h2> |
+ <h2 class="param-row margin-top">Optimization Problem</h2> |
|
<div class="param-row"> |
-{# <div id="problem_name" class="input button-padding-extra" contenteditable>{{ problem.name }}</div>#} |
<input id="problem_name" type="text" class="margin-small param-full auto-margin" value="{{ problem.name }}"/> |
</div> |
|
+ <div class="param-row"> |
+ <input id="problem_public" type="checkbox" class="" {{ "checked" if problem.public else "" }}/> |
+ Make Public |
+ </div> |
+ |
<h2 class="param-row">Algorithm Parameters</h2> |
|
<div class="param-row"> |
@@ -109,15 +117,27 @@ |
<div id="editor">{{ problem.code.strip()|safe }}</div> |
|
<div id="chartModal" class="chartModal"> |
- <div id="innerModal"> |
+ <div id="chartModalInner"> |
<div id="container" class="contained-chart"></div> |
<a href="#close" title="Close" class="close">X</a> |
</div> |
</div> |
|
<div id="openModal" class="openModal"> |
- <div> |
+ <div id="openModalInner"> |
+ <div class="flex-container-v"> |
+ <div class="param-full flex-fixed">Header</div> |
+ <div class="flex-fill-v problems-list-container"> |
+ <div id="problemsList" class="flex-container flex-center flex-wrap"> |
|
+ </div> |
+ </div> |
+ <div class="param-full flex-fixed">Footer</div> |
+ <a href="#close" title="Close" class="close">X</a> |
+ </div> |
+ </div> |
+ <div class="totally-hidden"> |
+ <div id="cursor"></div> |
</div> |
</div> |
|