diff --git a/css/app.css b/css/app.css
index 932ca3b52..f57611633 100644
--- a/css/app.css
+++ b/css/app.css
@@ -5,6 +5,7 @@ body {
font:normal 12px/1.6666 'Helvetica Neue', Arial, sans-serif;
margin:0;
padding:0;
+ min-width: 768px;
color:#222;
/* text-rendering: optimizeLegibility; */
-webkit-font-smoothing: subpixel-antialiased;
@@ -14,6 +15,11 @@ body {
height: 100%;
width: 100%;
position: fixed;
+ min-width: 768px;
+}
+
+.limiter {
+ max-width: 1200px;
}
div, textarea, input, span, ul, li, ol, a, button {
@@ -86,16 +92,21 @@ a:hover {
color:#154dff;
}
+
textarea,
input[type=text] {
background-color: white;
border:1px solid #ccc;
padding:10px;
+ resize: vertical;
}
-input[type=text] {
- padding:4px 10px;
- height:30px;
+.fillD textarea,
+.fillD input[type=text] {
+ background-color: black;
+ border:1px solid rgba(255, 255, 255, .25);
+ color: white;
+ border-radius: 4px;
}
textarea:focus,
@@ -103,6 +114,18 @@ input[type=text]:focus {
background-color: #ececec;
}
+.fillD textarea:focus,
+.fillD input[type=text]:focus {
+ background-color: black;
+ border:1px solid rgba(255, 255, 255, .5);
+}
+
+input[type=text] {
+ padding:4px 10px;
+ height:30px;
+ resize: none;
+}
+
/* tables */
table {
@@ -121,6 +144,36 @@ table.tags, table.tags td, table.tags th {
padding: 4px;
}
+/* Grid
+------------------------------------------------------- */
+
+.col0 { float:left; width:04.1666%; }
+.col1 { float:left; width:08.3333%; }
+.col2 { float:left; width:16.6666%; }
+.col3 { float:left; width:25.0000%; }
+.col4 { float:left; width:33.3333%; }
+.col5 { float:left; width:41.6666%; }
+.col6 { float:left; width:50.0000%; max-width: 600px; }
+.col7 { float:left; width:58.3333%; }
+.col8 { float:left; width:66.6666%; }
+.col9 { float:left; width:75.0000%; }
+.col10 { float:left; width:83.3333%; }
+.col11 { float:left; width:91.6666%; }
+.col12 { float:left; width:100.0000%; }
+.margin0 { margin-left: 04.1666%; }
+.margin1 { margin-left: 08.3333%; }
+.margin2 { margin-left: 16.6666%; }
+.margin3 { margin-left: 25.0000%; }
+.margin4 { margin-left: 33.3333%; }
+.margin5 { margin-left: 41.6666%; }
+.margin6 { margin-left: 50.0000%; }
+.margin7 { margin-left: 58.3333%; }
+.margin8 { margin-left: 66.6666%; }
+.margin9 { margin-left: 75.0000%; }
+.margin10 { margin-left: 83.3333%; }
+.margin11 { margin-left: 91.6666%; }
+.margin12 { margin-left: 100.0000%; }
+
/* UI Lists
------------------------------------------------------- */
@@ -128,13 +181,15 @@ ul li { list-style: none;}
ul.toggle-list li a {
font-weight: bold;
+ color: #c1c1c1;
padding: 10px;
- border-top: 1px solid #CCC;
+ border-top: 1px solid white;
display:block;
+ border-top: 1px solid rgba(0, 0, 0, .5);
}
-ul.toggle-list li a:hover {
- background: #ececec;
+ul.toggle-list li a.selected {
+ color: #333;
}
ul.toggle-list .icon {
@@ -142,20 +197,15 @@ ul.toggle-list .icon {
margin-right: 5px;
}
-a.selected {
- color:#222;
-}
-
-
ul.link-list li {
- float: left;
display: inline-block;
+ float: right;
margin-left: 10px;
padding-left: 10px;
border-left: 1px solid white;
}
-ul.link-list li:first-child {
+ul.link-list li:last-child {
border-left: 0;
margin-left: 0;
padding-left: 0;
@@ -163,12 +213,18 @@ ul.link-list li:first-child {
/* Utility Classes
------------------------------------------------------- */
+.fillL {
+ background: white;
+ color: #333;
+}
+
+.fillL2 {
+ background: #f7f7f7 url(../img/background-pattern-1.png) repeat;
+ color: #333;
+}
-.fillL { background-color: white;}
-.fillL2 { background: #f7f7f7 url(../img/background-pattern-1.png) repeat;}
.fillD {
- background-color: #222222;
- background-color: rgba(0,0,0,.8);
+ background:rgba(0,0,0,.8);
color: white;
}
@@ -181,9 +237,8 @@ form.hide {
}
.content {
- background-color:#fff;
border-radius: 4px;
- border: 1px solid #ccc;
+ box-shadow: 0 0 30px 0px rgba(0, 0, 0, 0.7);
}
.pad1 {padding: 10px;}
@@ -195,55 +250,38 @@ form.hide {
button {
line-height:20px;
- border:1px solid #aaa;
- box-shadow: inset 0 0 0px 1px #fff;
+ position: relative;
+ border:0;
color:#222;
background: white;
font-weight:bold;
- font-size:14px;
+ font-size:12px;
display: inline-block;
height:40px;
cursor:url(../img/cursor-pointer.png) 6 1, auto;
+ border-radius:4px;
}
button:hover {
background-color: #ececec;
}
+button.col3:hover {
+ background: #bde5aa;
+}
+
button.active {
- box-shadow: inset 0 0 0px 1px #fff, inset 0 0 6px 1px rgba(0,0,0,.35);
cursor:url(../img/cursor-pointing.png) 6 1, auto;
}
button.active:not([disabled]) {
- background-color: #ececec;
- box-shadow: inset 0 0 0px 1px #fff, inset 0 0 6px 1px rgba(0,0,0,.25);
-}
-
-button.wide,
-button.narrow {
- border-radius:4px;
-}
-
-button.wide {
- margin: 10px;
- width: 100px;
-}
-
-button.add-button {
- width: 80px;
-}
-
-button.narrow,
-button.Browse {
- width:40px;
+ background: #6bc641;
}
button.minor {
border-radius:4px;
height: 20px;
width: 20px;
- margin: 5px;
border: 0;
box-shadow: none;
background-color: transparent;
@@ -259,31 +297,34 @@ button.centered {
margin-right: auto;
}
-.buttons-joined {
+.button-wrap {
display: inline-block;
- margin:10px;
-}
-
-.buttons-joined button {
- border-right-width: 0;
- border-radius:0;
+ padding-right:10px;
margin: 0;
}
-.buttons-joined button:first-child {
+.button-wrap button:only-child { width: 100%;}
+.button-wrap:last-of-type { padding-right: 0;}
+
+.joined button {
+ border-right: 1px solid rgba(0,0,0,.5);
+ border-radius:0;
+}
+
+.joined button:first-child {
border-radius:4px 0 0 4px;
}
-.buttons-joined button:last-child {
- border-right-width: 1px;
+.joined button:last-child {
+ border-right-width: 0px;
border-radius:0 4px 4px 0;
}
button.action {
- background-color: #7092ff;
+ background: #7092ff;
}
button.action:hover {
- background-color: #6282ee;
+ background: #597BE7;
}
button.delete {
@@ -293,13 +334,6 @@ button.delete:hover {
background-color: #ef5454;
}
-button.save {
- background-color: #6bc641;
- min-width: 120px;
- width: auto;
- position: relative;
-}
-
button.save.has-count {
padding: 9px;
}
@@ -310,18 +344,31 @@ button.save .count {
button.save.has-count .count {
display: block;
- color: #6bc641;
- background: #fff;
- border-radius: 0 3px 3px 0;
- padding: 9px;
- float: right;
- margin-left: 10px;
- margin-top: -9px;
- margin-right: -8px;
+ position: absolute;
+ left: 115%;
+ top: 0;
+ bottom: 0;
+ background: rgba(255,255,255,.5);
+ color: #333;
+ padding: 10px;
+ height: 30px;
+ line-height: 12px;
+ border-radius: 4px;
+ margin: auto;
}
-button.save:hover {
- background-color: #59ac33;
+button.save.has-count .count::before {
+ content: "";
+ margin: auto;
+ width: 0;
+ height: 0;
+ position: absolute;
+ left: -6px;
+ top: 0;
+ bottom: 0;
+ border-top: 6px solid transparent;
+ border-bottom: 6px solid transparent;
+ border-right: 6px solid rgba(255,255,255,.5);
}
button.close {
@@ -330,28 +377,14 @@ button.close {
right: 10px;
}
-button .label {
- margin-right: 3px;
-}
-
-button.action .label {
- color: white;
- text-shadow: 0 -1px 0 rgba(0,0,0,.25);
-}
-
button[disabled] {
cursor:auto;
- background: white;
+ background: rgba(255,255,255,.5);
pointer-events:none;
}
button[disabled] .label {
- color:#ccc;
- text-shadow: none;
-}
-
-button[disabled]:hover {
- background: white;
+ color: rgba(0,0,0,.5);
}
/* Icons */
@@ -372,17 +405,17 @@ button[disabled]:hover {
}
.icon.icon-pre-text {
- margin-right: 3px;
+ margin-right: 3px;
}
/* Definitions for every icon */
+.icon.browse { background-position: 0px -20px;}
+.icon.add-point { background-position: -20px -20px;}
+.icon.add-line { background-position: -40px -20px;}
+.icon.add-area { background-position: -60px -20px;}
+.icon.undo { background-position: -80px -20px;}
+.icon.redo { background-position: -100px -20px;}
-.icon.browse { background-position: 0px 0px;}
-.icon.add-point { background-position: -20px 0px;}
-.icon.add-line { background-position: -40px 0px;}
-.icon.add-area { background-position: -60px 0px;}
-.icon.undo { background-position: -80px 0px;}
-.icon.redo { background-position: -100px 0px;}
.icon.apply { background-position: -120px 0px;}
.icon.save { background-position: -140px 0px;}
.icon.close { background-position: -160px 0px;}
@@ -395,25 +428,17 @@ button[disabled]:hover {
.icon.layers { background-position: -300px 0px;}
.icon.avatar { background-position: -320px 0px;}
.icon.nearby { background-position: -340px 0px;}
+.icon.geolocate { background-position: -360px 0px;}
-.fillD .icon.browse { background-position: 0px -20px;}
-.fillD .icon.add-point { background-position: -20px -20px;}
-.fillD .icon.add-line { background-position: -40px -20px;}
-.fillD .icon.add-area { background-position: -60px -20px;}
-.fillD .icon.undo { background-position: -80px -20px;}
-.fillD .icon.redo { background-position: -100px -20px;}
-.fillD .icon.apply { background-position: -120px -20px;}
-.fillD .icon.save { background-position: -140px -20px;}
-.fillD .icon.close { background-position: -160px -20px;}
-.fillD .icon.delete { background-position: -180px -20px;}
-.fillD .icon.remove { background-position: -200px -20px;}
-.fillD .icon.inspect { background-position: -220px -20px;}
-.fillD .icon.zoom-in { background-position: -240px -20px;}
-.fillD .icon.zoom-out { background-position: -260px -20px;}
-.fillD .icon.geocode { background-position: -280px -20px;}
-.fillD .icon.layers { background-position: -300px -20px;}
-.fillD .icon.avatar { background-position: -320px -20px;}
-.fillD .icon.nearby { background-position: -340px -20px;}
+.icon.browse { background-position: 0px 0px;}
+.icon.add-point { background-position: -20px 0px;}
+.icon.add-line { background-position: -40px 0px;}
+.icon.add-area { background-position: -60px 0px;}
+.icon.undo { background-position: -80px 0px;}
+.icon.redo { background-position: -100px 0px;}
+
+.fillD .icon.avatar { background-position: -320px -20px;}
+.fillD .icon.nearby { background-position: -340px -20px;}
button[disabled] .icon.browse { background-position: 0px -40px;}
button[disabled] .icon.add-point { background-position: -20px -40px;}
@@ -440,7 +465,7 @@ button[disabled] .icon.nearby { background-position: -340px -40px;}
.icon.big-vertex { background-position: -120px -80px;}
.icon.big-inspect { background-position: -160px -80px;}
-/* Toggle Icon is special */
+/* Toggle icon is special */
.toggle.icon { background-position: 0px -180px;}
a:hover .toggle.icon { background-position: -20px -180px;}
.selected .toggle.icon,
@@ -450,46 +475,49 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
------------------------------------------------------- */
#bar {
- border-bottom:1px solid #ccc;
position:absolute;
left:0px;
top:0px;
right:0;
height:60px;
+ border-radius: 0;
+ -webkit-transition: opacity .25s, z-index 0 0s;
+ -moz-transition: opacity .25s, z-index 0 0s;
+ transition: opacity .25s, z-index 0 0s;
}
-/* Special rules for toolbar icons */
-
-button.Browse .label {
- display: none;
- }
-
-/* Status box */
-
-.messages {
- display:none;
+.mode-add-point #bar,
+.mode-add-line #bar,
+.mode-draw-line #bar,
+.mode-draw-area #bar,
+.mode-add-area #bar {
+ opacity:0;
+ z-index: -9999;
+ -webkit-transition: opacity .25s, z-index 0 .5s;
+ -moz-transition: opacity .25s, z-index 0 .5s;
+ transition: opacity .25s, z-index 0 .5s;
}
/* Inspector */
.inspector-wrap {
- position:absolute;
- right: 0;
- border-left: 1px solid #ccc;
- border-bottom: 1px solid #ccc;
- min-height: 60px;
opacity:0;
display:none;
+ padding-left: 10px;
+ max-width: 500px;
+}
+
+.inspector {
+ min-height: 60px;
+ position: relative;
+ border-radius: 0 0 0 10px;
}
.inspector-inner {
padding: 10px;
- min-width:400px;
}
.inspector-inner.head {
- border-bottom: 1px solid #ccc;
- background:#fff;
z-index:1;
position:relative;
}
@@ -518,8 +546,8 @@ button.Browse .label {
}
.tag-row {
- width: 100%;
- padding-right: 70px;
+ width: 80%;
+ padding-right: 0px;
position: relative;
height: 30px;
}
@@ -560,27 +588,40 @@ button.Browse .label {
.tag-row button {
position: absolute;
- top: 0;
- right: 0;
+ top: 5px;
+ right: -60px;
}
.tag-row button.tag-help {
- right: 30px;
+ right: -30px;
+}
+.inspector-buttons {
+ border-radius: 0 0 0 10px;
+ height: 60px;
}
-.inspector-buttons {
- border-top: 1px solid #ccc;
+.inspector-buttons .button-wrap {
+ width: 40%;
+ padding-right: 0;
+}
+
+.inspector-buttons .minor-buttons {
+ padding-left: 10px;
+ line-height: 40px;
+ width: 60%;
}
.inspector-inner .add-tag-row {
width: 100%;
- padding-right: 70px;
+}
+
+.inspector-inner .add-tag-row button {
+ border-radius: 0 0 4px 4px;
}
.inspector-inner .add-tag {
- width: 50%;
+ width: 40%;
height: 30px;
- font-size: 100%;
border: 1px solid #ccc;
border-top: 0;
}
@@ -588,16 +629,31 @@ button.Browse .label {
/* Map Controls */
.map-control {
- left:10px;
+ left:0px;
position:absolute;
}
+.map-control button {
+ width: 40px;
+ background: rgba(0,0,0,.8);
+ border-radius: 0 4px 4px 0;
+}
+
+.map-control button:hover {
+ background: rgba(0, 0, 0, .9);
+}
+
+.map-control button.active:hover {
+ background: #6bc641;
+}
+
.map-overlay {
width: 150px;
position:absolute;
left:50px;
top:0;
display: block;
+ border-radius: 4px;
}
/* Zoomer */
@@ -608,12 +664,13 @@ button.Browse .label {
}
.zoombuttons button.zoom-in {
- border-radius:4px 4px 0 0;
+ border-radius:0 4px 0 0;
+ border-bottom: 1px solid rgba(0, 0, 0, .5);
}
.zoombuttons button.zoom-out {
border-top:0;
- border-radius:0 0 4px 4px;
+ border-radius:0 0 4px 0;
}
/* Layer Switcher */
@@ -622,28 +679,24 @@ button.Browse .label {
top:210px;
}
-.layerswitcher-control .adjustments {
- padding:5px;
- opacity:0.2;
-}
-
-.layerswitcher-control .adjustments:hover {
- opacity:1;
-}
-
-.layerswitcher-control .adjustments .reset {
+.layerswitcher-control .adjustments button {
+ opacity:0.5;
height:20px;
font-size:10px;
font-weight:normal;
- padding:0 5px;
+ padding:0 5px 3px 5px;
+ background: white;
+ border: 1px solid #ddd;
+ border-radius: 0;
+}
+
+.layerswitcher-control .adjustments button:hover {
+ opacity: 1;
}
.layerswitcher-control .nudge {
- height:20px;
width:20px;
- font-size:10px;
margin-right:2px;
- font-weight:normal;
}
.opacity-options-wrapper {
@@ -651,7 +704,6 @@ button.Browse .label {
}
.opacity-options {
- border:1px solid #b0b0b0;
background: url(../img/background-pattern-opacity.png) 0 0 repeat;
height:20px;
width:62px;
@@ -670,14 +722,14 @@ button.Browse .label {
.opacity-options li .select-box{
position: absolute;
width:20px;
- height:18px;
+ height:20px;
z-index: 9999;
}
.layerswitcher-control li:hover .select-box,
.layerswitcher-control li.selected .select-box {
- border: 2px solid #4672ff;
- background: rgba(70, 114, 255, .5);
+ border: 2px solid #6bc641;
+ background: rgba(107, 198, 65, .5);
opacity: .5;
}
.layerswitcher-control li.selected:hover .select-box,
@@ -689,7 +741,7 @@ button.Browse .label {
background:#222;
display:inline-block;
width:20px;
- height:18px;
+ height:20px;
}
/* Geocoder */
@@ -715,7 +767,7 @@ button.Browse .label {
display:block;
position:absolute;
overflow:hidden;
- top:60px;
+ top:0px;
left:0;
right:0;
bottom:0;
@@ -740,29 +792,18 @@ img.tile {
------------------------------------------------------- */
.about-block {
- float: right;
height: 40px;
-}
-
-#about {
- border-radius:3px 0 0 0;
-}
-
-#attrib-container {
position: absolute;
right:0px;
bottom:0px;
-}
-
-#user-list {
- margin-right: 8px;
- border-radius:3px 3px 0 0;
- max-width: 400px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
+ border-radius: 0;
}
+#about { text-align: right;}
+
#user-list a:not(:last-child):after {
content: ', ';
}
@@ -770,10 +811,7 @@ img.tile {
/* Account Information */
.user-container {
- position:absolute;
- left:0px;
- bottom:0px;
- border-radius:0 3px 0 0;
+ float: left;
}
.user-container .logout {
@@ -826,6 +864,7 @@ div.typeahead a:first-child {
position:absolute;
width: 50%;
left: 25%;
+ max-width: 600px;
top:80px;
z-index: 3;
}
@@ -840,15 +879,16 @@ div.typeahead a:first-child {
text-align: center;
}
-.modal button { margin-bottom: 0;}
-.modal button:first-child { margin-left: 0;}
-
.modal button.close-modal {
float:right;
- margin-right:10px;
- margin-top:10px;
+ position: absolute;
+ right:5px;
+ top:5px;
border:0;
}
+.modal button.close-modal:hover {
+ background-color: transparent;
+}
.shaded {
z-index: 2;
@@ -893,10 +933,20 @@ div.typeahead a:first-child {
.modal-section {
padding: 20px;
- border-bottom: 1px solid #ccc;
}
-.modal-section:last-child { border-bottom: 0;}
+.modal-section.header {
+ border-radius: 4px 4px 0 0;
+}
+
+.modal-section:last-child {
+ border-radius: 0 0 4px 4px;
+}
+
+.modal-section .buttons {
+ padding-top: 10px;
+ width: 100%;
+}
.modal-section img.wiki-image {
max-width: 400px;
@@ -955,18 +1005,16 @@ div.typeahead a:first-child {
.tooltip {
white-space: normal;
position: absolute;
+ left: 0; right: 0; margin: auto;
z-index: -1000;
height: 0;
padding: 5px;
opacity: 0;
display: block;
- filter: alpha(opacity=0);
- visibility: visible;
}
.tooltip.in {
opacity: 0.8;
- filter: alpha(opacity=80);
z-index: 1030;
height: auto;
}
@@ -988,16 +1036,14 @@ div.typeahead a:first-child {
}
.tooltip-inner {
- max-width: 200px;
- min-width: 100px;
+ text-align: left;
+ width: 200px;
font-size: 11px;
font-weight: bold;
line-height: 20px;
padding: 5px 10px;
- color: #ffffff;
- text-align: center;
- text-decoration: none;
- background-color: #000000;
+ color: #333;
+ background-color: white;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
@@ -1015,7 +1061,7 @@ div.typeahead a:first-child {
bottom: 0;
left: 50%;
margin-left: -5px;
- border-top-color: #000000;
+ border-top-color: white;
border-width: 5px 5px 0;
}
@@ -1023,7 +1069,7 @@ div.typeahead a:first-child {
top: 50%;
left: 0;
margin-top: -5px;
- border-right-color: #000000;
+ border-right-color: white;
border-width: 5px 5px 5px 0;
}
@@ -1031,7 +1077,7 @@ div.typeahead a:first-child {
top: 50%;
right: 0;
margin-top: -5px;
- border-left-color: #000000;
+ border-left-color: white;
border-width: 5px 0 5px 5px;
}
@@ -1039,7 +1085,7 @@ div.typeahead a:first-child {
top: 0;
left: 50%;
margin-left: -5px;
- border-bottom-color: #000000;
+ border-bottom-color: white;
border-width: 0 5px 5px;
}
@@ -1058,3 +1104,13 @@ div.typeahead a:first-child {
-moz-border-radius: 4px;
border-radius: 4px;
}
+
+/* Media Queries
+------------------------------------------------------- */
+
+@media only screen and (max-width: 840px) {
+ span.label {display: none;}
+ /* override hide for save button */
+ .icon.icon-pre-text { margin-right: 0px;}
+ .save .label { display: block;}
+}
diff --git a/css/map.css b/css/map.css
index 5d529ea55..833ff39b6 100644
--- a/css/map.css
+++ b/css/map.css
@@ -7,7 +7,7 @@ g.point circle {
fill:#fff;
}
-g.point.hover circle.stroke,
+g.pointer circle.stroke,
g.point.selected circle.stroke {
fill:#333;
-webkit-transform:scale(1.2, 1.2);
@@ -15,131 +15,150 @@ g.point.selected circle.stroke {
transform:scale(1.2, 1.2);
}
-/* interactive elements */
-g.vertex circle.fill {
+/* vertices */
+
+g.vertex .fill {
+ fill:white;
+}
+g.vertex .stroke {
+ stroke:#333;
+ stroke-width:2;
fill:white;
- fill-opacity:1;
}
-circle.stroke,
-circle.fill {
- -webkit-transition: -webkit-transform 50ms linear;
- transition: transform 50ms linear;
- -moz-transition: stroke 50ms linear;
- -webkit-transform:scale(1, 1);
- -moz-transform:scale(1, 1);
- transform:scale(1, 1);
+svg[data-zoom="16"] g.vertex .shadow {
+ -webkit-transform:scale(0.8, 0.8);
+ -moz-transform:scale(0.8, 0.8);
+ transform:scale(0.8, 0.8);
}
-
-svg[data-zoom="16"] g.vertex circle.stroke,
-svg[data-zoom="16"] g.vertex circle.fill {
+svg[data-zoom="16"] g.vertex .stroke,
+svg[data-zoom="16"] g.vertex .fill {
-webkit-transform:scale(0.6, 0.6);
-moz-transform:scale(0.6, 0.6);
transform:scale(0.6, 0.6);
}
-svg[data-zoom="17"] g.vertex circle.stroke,
-svg[data-zoom="17"] g.vertex circle.fill {
+svg[data-zoom="17"] g.vertex .shadow {
+ -webkit-transform:scale(0.9, 0.9);
+ -moz-transform:scale(0.9, 0.9);
+ transform:scale(0.9, 0.9);
+}
+svg[data-zoom="17"] g.vertex .stroke,
+svg[data-zoom="17"] g.vertex .fill {
-webkit-transform:scale(0.7, 0.7);
-moz-transform:scale(0.7, 0.7);
transform:scale(0.7, 0.7);
}
-path.casing.tag-highway {
- stroke-width:10;
+g.vertex.shared .shadow {
+ -webkit-transform:scale(1.2, 1.2);
+ -moz-transform:scale(1.2, 1.2);
+ transform:scale(1.2, 1.2);
+}
+g.vertex.shared .fill,
+g.vertex.shared .stroke {
+ -webkit-transform:scale(1.1, 1.1);
+ -moz-transform:scale(1.1, 1.1);
+ transform:scale(1.1, 1.1);
+}
+svg[data-zoom="16"] g.vertex.shared .shadow {
+ -webkit-transform:scale(0.9, 0.9);
+ -moz-transform:scale(0.9, 0.9);
+ transform:scale(0.9, 0.9);
+}
+svg[data-zoom="16"] g.vertex.shared .fill,
+svg[data-zoom="16"] g.vertex.shared .stroke {
+ -webkit-transform:scale(0.8, 0.8);
+ -moz-transform:scale(0.8, 0.8);
+ transform:scale(0.8, 0.8);
+}
+svg[data-zoom="17"] g.vertex.shared .shadow {
+ -webkit-transform:scale(1, 1);
+ -moz-transform:scale(1, 1);
+ transform:scale(1, 1);
+}
+svg[data-zoom="17"] g.vertex.shared .fill,
+svg[data-zoom="17"] g.vertex.shared .stroke {
+ -webkit-transform:scale(0.9, 0.9);
+ -moz-transform:scale(0.9, 0.9);
+ transform:scale(0.9, 0.9);
}
-path.stroke.tag-highway {
- stroke-width:8;
-}
-
-svg[data-zoom="16"] path.casing.tag-highway {
- stroke-width:6;
-}
-
-svg[data-zoom="16"] path.stroke.tag-highway {
- stroke-width:4;
-}
-
-g.vertex circle.stroke {
- fill:#333;
-}
-
-g.vertex.shared circle.fill {
- fill:#aff;
-}
-g.vertex.shared circle.stroke {
- fill:#044;
-}
-
-g.vertex.hover circle.fill {
- -webkit-transform:scale(1.5, 1.5);
- -moz-transform:scale(1.5, 1.5);
- transform:scale(1.5, 1.5);
-}
-
-g.vertex.hover circle.stroke {
- -webkit-transform:scale(1.4, 1.4);
- -moz-transform:scale(1.4, 1.4);
- transform:scale(1.4, 1.4);
-}
-
-g.vertex circle.selected.fill {
- fill: #ffff00;
-}
-g.vertex circle.selected.stroke {
- fill: #38380A;
-}
-
-circle.midpoint {
+g.vertex.shared .fill {
fill:#aaa;
- stroke:#333;
- fill-opacity:1;
- stroke-width:1;
}
-circle.teaser-point {
- stroke-width: 2;
- stroke:#1DCAFF;
- fill:#D3F5FF;
+g.vertex .shadow {
+ fill: none;
+ pointer-events: all;
+ stroke-width: 10;
+ -webkit-transition: -webkit-transform 100ms linear;
+ transition: transform 100ms linear;
+ -moz-transition: fill 100ms linear;
+}
+g.vertex.hover .shadow {
+ fill: #E96666;
+ fill-opacity: 0.3;
+}
+g.vertex.selected .shadow {
+ fill: #E96666;
+ fill-opacity: 0.7;
}
-path.casing {
- stroke: #111;
- stroke-linecap:round;
- stroke-linejoin:bevel;
- stroke-width: 3;
- -webkit-transition: stroke 100ms linear;
+/* midpoints */
+
+g.midpoint .fill {
+ fill:#aaa;
+}
+g.midpoint .fill.hover {
+ fill:#fff;
+ stroke:#000;
}
-path.casing.hover {
- stroke:#FF0F0F !important;
- stroke-opacity:0.8;
+g.midpoint .shadow {
+ fill: none;
+ pointer-events: all;
+ stroke-width: 10;
+ -webkit-transition: -webkit-transform 100ms linear;
+ transition: transform 100ms linear;
+ -moz-transition: fill 100ms linear;
+}
+g.midpoint .shadow.hover {
+ fill:#E96666;
+ fill-opacity: 0.3;
}
-path.casing.selected {
- stroke:#E96666 !important;
- stroke-opacity:1 !important;
- stroke-width:10 !important;
+/* lines */
+
+path.line {
+ stroke-linecap: round;
+ stroke-linejoin: bevel;
}
path.stroke {
- stroke: #555;
- stroke-linecap:round;
- stroke-linejoin:bevel;
+ stroke: #222;
stroke-width: 2;
}
-path.stroke.tag-railway-rail {
- stroke: white;
- stroke-width: 3;
- stroke-dasharray: 12,12;
+path.stroke,
+path.casing {
+ shape-rendering: optimizeSpeed;
}
-path.stroke.tag-railway-subway {
- stroke: #444;
- stroke-width: 3;
- stroke-dasharray: 8,8;
+path.shadow {
+ pointer-events: stroke;
+ stroke-width: 10;
+ -webkit-transition: stroke 100ms linear;
+}
+
+path.shadow.hover {
+ stroke: #E96666;
+ stroke-opacity: 0.3;
+}
+
+path.shadow.selected {
+ stroke: #E96666;
+ stroke-opacity: 0.7;
}
path.area,
@@ -206,81 +225,209 @@ path.multipolygon.tag-amenity-parking {
}
/* highways */
-path.stroke.tag-highway-residential {
- stroke:#fff;
+
+path.shadow.tag-highway {
+ stroke-width:16;
}
-path.casing.tag-highway-residential {
+path.casing.tag-highway {
stroke:#444;
+ stroke-width:10;
+}
+path.stroke.tag-highway {
+ stroke:#ccc;
+ stroke-width:8;
+}
+
+svg[data-zoom="16"] path.shadow.tag-highway {
+ stroke-width:12;
+}
+svg[data-zoom="16"] path.casing.tag-highway {
+ stroke-width:6;
+}
+svg[data-zoom="16"] path.stroke.tag-highway {
+ stroke-width:4;
+}
+
+path.stroke.tag-highway-motorway,
+path.stroke.tag-highway-motorway_link,
+path.stroke.tag-construction-motorway {
+ stroke:#809bc0;
+}
+path.casing.tag-highway-motorway,
+path.casing.tag-highway-motorway_link,
+path.casing.tag-construction-motorway {
+ stroke:#506077;
+}
+
+path.stroke.tag-highway-trunk,
+path.stroke.tag-highway-trunk_link,
+path.stroke.tag-construction-trunk {
+ stroke:#97d397;
+}
+path.casing.tag-highway-trunk,
+path.casing.tag-highway-trunk_link,
+path.casing.tag-construction-trunk {
+ stroke:#477147;
+}
+
+path.stroke.tag-highway-primary,
+path.stroke.tag-highway-primary_link,
+path.stroke.tag-construction-primary {
+ stroke:#ec989a;
+}
+path.casing.tag-highway-primary,
+path.casing.tag-highway-primary_link,
+path.casing.tag-construction-primary {
+ stroke:#8d4346;
+}
+
+path.stroke.tag-highway-secondary,
+path.stroke.tag-highway-secondary_link,
+path.stroke.tag-construction-secondary {
+ stroke:#fecc8b;
+}
+path.casing.tag-highway-secondary,
+path.casing.tag-highway-secondary_link,
+path.casing.tag-construction-secondary {
+ stroke:#a37b48;
+}
+
+path.stroke.tag-highway-tertiary,
+path.stroke.tag-highway-tertiary_link,
+path.stroke.tag-construction-tertiary {
+ stroke:#ffffb3;
+}
+path.casing.tag-highway-tertiary,
+path.casing.tag-highway-tertiary_link,
+path.casing.tag-construction-tertiary {
+ stroke:#bbb;
}
path.stroke.tag-highway-unclassified,
-path.stroke.tag-highway-tertiary,
-path.stroke.tag-highway-tertiary_link {
- stroke:#FEFECB;
+path.stroke.tag-construction-unclassified {
+ stroke:#eaeaea;
+}
+path.casing.tag-highway-unclassified,
+path.casing.tag-construction-unclassified {
+ stroke:#444;
}
-path.casing.tag-highway-unclassified,
-path.casing.tag-highway-tertiary,
-path.casing.tag-highway-tertiary_link { }
+path.stroke.tag-highway-residential,
+path.stroke.tag-construction-residential {
+ stroke:#fff;
+}
+path.casing.tag-highway-residential,
+path.casing.tag-construction-residential {
+ stroke:#444;
+}
-path.stroke.tag-highway-service {
+path.stroke.tag-highway-living_street {
+ stroke:#ccc;
+ stroke-width:4;
+}
+path.casing.tag-highway-living_street {
stroke:#fff;
stroke-width:6;
}
+
+path.stroke.tag-highway-pedestrian {
+ stroke:#fff;
+ stroke-dasharray: 2, 8;
+ stroke-width:4 !important;
+ shapeRendering: auto;
+}
+path.casing.tag-highway-pedestrian {
+ stroke:#84C382;
+ stroke-width:6 !important;
+}
+
+path.stroke.tag-highway-service {
+ stroke:#fff;
+ stroke-width:4;
+}
path.casing.tag-highway-service {
- stroke-width:8;
+ stroke:#666;
+ stroke-width:6;
+}
+svg[data-zoom="16"] path.stroke.tag-highway-service {
+ stroke-width:2;
+}
+svg[data-zoom="16"] path.casing.tag-highway-service {
+ stroke-width:4;
+}
+
+path.stroke.tag-highway-track {
+ stroke: #fff;
+ stroke-width: 4;
+}
+path.casing.tag-highway-track {
+ stroke: #996600;
+ stroke-width: 6;
+ stroke-linecap: butt;
+ stroke-dasharray: 6, 6;
+}
+svg[data-zoom="16"] path.stroke.tag-highway-track {
+ stroke-width:2;
+}
+svg[data-zoom="16"] path.casing.tag-highway-track {
+ stroke-width:4;
+}
+
+path.stroke.tag-highway-path {
+ stroke: #000;
+ stroke-width: 1 !important;
+ stroke-linecap: butt;
+ stroke-dasharray: 8, 4;
+}
+path.casing.tag-highway-path {
+ stroke-width: 1 !important;
+ stroke: #fff;
}
path.stroke.tag-highway-footway,
path.stroke.tag-highway-cycleway,
-path.stroke.tag-highway-steps {
- stroke: #ff6257;
+path.stroke.tag-highway-bridleway {
stroke-width: 4;
+ stroke-linecap: butt;
stroke-dasharray: 6, 6;
}
path.casing.tag-highway-footway,
path.casing.tag-highway-cycleway,
-path.casing.tag-highway-steps {
+path.casing.tag-highway-bridleway {
stroke-width: 6;
stroke: #fff;
}
-path.stroke.tag-highway-motorway,
-path.stroke.tag-highway-motorway_link {
- stroke:#809BC0;
+svg[data-zoom="16"] path.stroke.tag-highway-footway,
+svg[data-zoom="16"] path.stroke.tag-highway-cycleway,
+svg[data-zoom="16"] path.stroke.tag-highway-bridleway {
+ stroke-width: 2;
}
-path.casing.tag-highway-motorway,
-path.casing.tag-highway-motorway_link {
- stroke:#809BC0;
- stroke-opacity:0.4;
+svg[data-zoom="16"] path.casing.tag-highway-footway,
+svg[data-zoom="16"] path.casing.tag-highway-cycleway,
+svg[data-zoom="16"] path.casing.tag-highway-bridleway {
+ stroke-width: 4;
}
-path.stroke.tag-highway-trunk,
-path.stroke.tag-highway-trunk_link {
- stroke-opacity:0.4;
- stroke:#7FC97F;
+path.stroke.tag-highway-footway {
+ stroke: #996600;
}
-path.casing.tag-highway-trunk,
-path.casing.tag-highway-trunk_link {
- stroke:#7FC97F;
+path.stroke.tag-highway-cycleway {
+ stroke: #69f;
+}
+path.stroke.tag-highway-bridleway {
+ stroke: green;
}
-path.stroke.tag-highway-primary,
-path.stroke.tag-highway-primary_link {
- stroke:#ec989a;
+path.stroke.tag-highway-steps {
+ stroke: #ff6257;
+ stroke-width: 4;
+ stroke-linecap: butt;
+ stroke-dasharray: 3, 3;
}
-path.casing.tag-highway-primary,
-path.casing.tag-highway-primary_link {
- stroke:#681212;
-}
-
-path.stroke.tag-highway-secondary,
-path.stroke.tag-highway-secondary_link {
- stroke:#FDBF6F;
-}
-path.casing.tag-highway-secondary,
-path.casing.tag-highway-secondary_link {
- stroke:#444;
+path.casing.tag-highway-steps {
+ stroke-width: 6;
+ stroke: #fff;
}
path.casing.tag-bridge-yes {
@@ -288,11 +435,108 @@ path.casing.tag-bridge-yes {
stroke: #000;
}
+path.stroke.tag-highway-construction,
+path.casing.tag-highway-construction {
+ stroke-linecap: butt;
+ stroke-dasharray: 7, 7;
+}
+
+svg[data-zoom="16"] path.stroke.tag-highway-construction,
+svg[data-zoom="16"] path.casing.tag-highway-construction {
+ stroke-linecap: butt;
+ stroke-dasharray: 5, 5;
+}
+
+/* railways */
+
+path.stroke.tag-railway {
+ stroke: #eee;
+ stroke-width: 2;
+ stroke-linecap: butt;
+ stroke-dasharray: 12,12;
+}
+path.casing.tag-railway {
+ stroke: #555;
+ stroke-width: 4;
+}
+
+path.stroke.tag-railway-abandoned {
+ stroke: #eee;
+}
+path.casing.tag-railway-abandoned {
+ stroke: #999;
+}
+
+path.stroke.tag-railway-subway {
+ stroke: #666;
+}
+path.casing.tag-railway-subway {
+ stroke: #222;
+}
+
+/* waterways */
+
path.stroke.tag-waterway {
stroke: #10539a;
+ stroke-width: 2;
+}
+path.casing.tag-waterway {
+ stroke: #6AA2FF;
+ stroke-width: 4;
+}
+
+path.stroke.tag-waterway-river {
+ stroke-width: 4;
+}
+path.casing.tag-waterway-river {
+ stroke-width: 6;
+}
+
+svg[data-zoom="16"] path.stroke.tag-waterway-river {
+ stroke-width: 4;
+}
+svg[data-zoom="16"] path.casing.tag-waterway-river {
+ stroke-width: 6;
+}
+
+path.stroke.tag-waterway-ditch {
+ stroke: #10539a;
+ stroke-width: 1;
+}
+path.casing.tag-waterway-ditch {
+ stroke: #999692;
stroke-width: 3;
}
+/* power */
+
+path.stroke.tag-power {
+ stroke: #939393;
+ stroke-width: 2;
+}
+path.casing.tag-power {
+ stroke: none;
+}
+
+/* boundary */
+
+path.stroke.tag-boundary {
+ stroke: #fff;
+ stroke-width: 2;
+ stroke-linecap: butt;
+ stroke-dasharray: 20, 5, 5, 5;
+}
+path.casing.tag-boundary {
+ stroke: #82B5FE;
+ stroke-width: 6;
+}
+
+path.casing.tag-boundary-protected_area,
+path.casing.tag-boundary-national_park {
+ stroke: #4D9849;
+}
+
+
text {
font-size:10px;
pointer-events: none;
diff --git a/img/source/sprite.svg b/img/source/sprite.svg
index f239c672f..537a84226 100644
--- a/img/source/sprite.svg
+++ b/img/source/sprite.svg
@@ -9,11 +9,11 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="360"
+ width="380"
height="200"
id="svg12393"
version="1.1"
- inkscape:version="0.48.2 r9819"
+ inkscape:version="0.48.1 r9760"
sodipodi:docname="sprite.svg"
inkscape:export-filename="/Users/saman/work_repos/iD/img/sprite.png"
inkscape:export-xdpi="90"
@@ -38,9 +38,9 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
- inkscape:zoom="1"
- inkscape:cx="150.66428"
- inkscape:cy="90.493266"
+ inkscape:zoom="2.8284271"
+ inkscape:cx="173.1037"
+ inkscape:cy="123.12989"
inkscape:document-units="px"
inkscape:current-layer="layer12"
showgrid="false"
@@ -56,7 +56,7 @@
showguides="false"
inkscape:guide-bbox="true"
inkscape:snap-bbox="true"
- inkscape:snap-nodes="true">
+ inkscape:snap-nodes="false">
+
+
@@ -175,110 +183,15 @@
id="layer1"
transform="translate(-25,-62.362183)"
style="display:inline">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
+ transform="translate(-25,3.0625e-6)">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ style="color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
@@ -935,26 +499,6 @@
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ style="fill:#ffffff;fill-opacity:1;display:inline">
+ style="fill:#ffffff;fill-opacity:1;display:inline">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1260,30 +583,12 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
+ d="m 90,44 -1,1 0,2 1,1 0,4 -1,1 0,2 1,1 2,0 1,-1 4,0 1,1 2,0 1,-1 0,-2 -1,-1 0,-4 1,-1 0,-2 -1,-1 -2,0 -1,1 -4,0 -1,-1 -2,0 z m 1,1 c 0.55228,0 1,0.447715 1,1 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 z m 8,0 c 0.55228,0 1,0.447715 1,1 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 z m -6,2 4,0 1,1 0,4 -1,1 -4,0 -1,-1 0,-4 1,-1 z m -2,6 c 0.55228,0 1,0.447715 1,1 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 z m 8,0 c 0.55228,0 1,0.447715 1,1 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 z"
+ id="path16225" />
+ style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
+ d="m 79,43.000003 -1,1 0,1.59375 -6.40625,6.40625 -1.59375,0 -1,1 0,2 1,1 2,0 1,-1 0,-1.59375 6.40625,-6.40625 1.59375,0 1,-1 0,-2 -1,-1 -2,0 z m 1,1 c 0.55228,0 1,0.44772 1,1 0,0.55229 -0.44772,1 -1,1 -0.25152,0 -0.48052,-0.0967 -0.65625,-0.25 -0.0344,-0.03002 -0.0637,-0.05934 -0.0937,-0.09375 C 79.0967,45.480522 79,45.251524 79,45.000003 c 0,-0.55228 0.44772,-1 1,-1 z m -9,9 c 0.25152,0 0.48052,0.0967 0.65625,0.25 l 0.0937,0.09375 C 71.9033,53.519484 72,53.748487 72,54.000003 c 0,0.55229 -0.44772,1 -1,1 -0.55228,0 -1,-0.44771 -1,-1 0,-0.55228 0.44772,-1 1,-1 z"
+ id="path16227" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/img/sprite.png b/img/sprite.png
index 2f933d9f8..e3037eebd 100644
Binary files a/img/sprite.png and b/img/sprite.png differ
diff --git a/index.html b/index.html
index bbefb2c04..318bc54a8 100644
--- a/index.html
+++ b/index.html
@@ -73,6 +73,7 @@
+
diff --git a/js/id/actions/add_relation_member.js b/js/id/actions/add_relation_member.js
new file mode 100644
index 000000000..45e24a0b0
--- /dev/null
+++ b/js/id/actions/add_relation_member.js
@@ -0,0 +1,9 @@
+iD.actions.AddRelationMember = function(relationId, member, index) {
+ return function(graph) {
+ var relation = graph.entity(relationId),
+ members = relation.members.slice();
+
+ members.splice((index === undefined) ? members.length : index, 0, member);
+ return graph.replace(relation.update({members: members}));
+ };
+};
diff --git a/js/id/actions/reverse_way.js b/js/id/actions/reverse_way.js
index 37ac53f10..a845fe844 100644
--- a/js/id/actions/reverse_way.js
+++ b/js/id/actions/reverse_way.js
@@ -65,7 +65,7 @@ iD.actions.ReverseWay = function(wayId) {
graph.parentRelations(way).forEach(function (relation) {
relation.members.forEach(function (member, index) {
if (member.id === way.id && (role = {forward: 'backward', backward: 'forward'}[member.role])) {
- graph = iD.actions.UpdateRelationMember(relation.id, index, {role: role})(graph);
+ graph = iD.actions.UpdateRelationMember(relation.id, {role: role}, index)(graph);
}
});
});
diff --git a/js/id/actions/split_way.js b/js/id/actions/split_way.js
index 6682ab638..de399df80 100644
--- a/js/id/actions/split_way.js
+++ b/js/id/actions/split_way.js
@@ -1,5 +1,13 @@
-// https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
-iD.actions.SplitWay = function(nodeId) {
+// Split a way at the given node.
+//
+// For testing convenience, accepts an ID to assign to the new way.
+// Normally, this will be undefined and the way will automatically
+// be assigned a new ID.
+//
+// Reference:
+// https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
+//
+iD.actions.SplitWay = function(nodeId, newWayId) {
return function(graph) {
var node = graph.entity(nodeId),
parents = graph.parentWays(node);
@@ -7,38 +15,44 @@ iD.actions.SplitWay = function(nodeId) {
// splitting ways at intersections TODO
if (parents.length !== 1) return graph;
- var way = parents[0];
-
- var idx = _.indexOf(way.nodes, nodeId);
+ var way = parents[0],
+ idx = _.indexOf(way.nodes, nodeId);
// Create a 'b' way that contains all of the tags in the second
// half of this way
- var newWay = iD.Way({ tags: _.clone(way.tags), nodes: way.nodes.slice(idx) });
+ var newWay = iD.Way({id: newWayId, tags: way.tags, nodes: way.nodes.slice(idx)});
graph = graph.replace(newWay);
// Reduce the original way to only contain the first set of nodes
- graph = graph.replace(way.update({ nodes: way.nodes.slice(0, idx + 1) }), 'changed way direction');
+ graph = graph.replace(way.update({nodes: way.nodes.slice(0, idx + 1)}));
- var parentRelations = graph.parentRelations(way);
-
- function isVia(x) { return x.role = 'via'; }
- function isSelf(x) { return x.id = way.id; }
-
- parentRelations.forEach(function(relation) {
- if (relation.tags.type === 'restriction') {
- var via = _.find(relation.members, isVia);
- var ownrole = _.find(relation.members, isSelf).role;
- if (via && !_.contains(newWay.nodes, via.id)) {
- // the new way doesn't contain the node that's important
- // to the turn restriction, so we don't need to worry
- // about adding it to the turn restriction.
- } else {
- graph = graph.replace(iD.actions.AddRelationMember(relation.id, {
- role: ownrole,
- id: newWay.id,
- type: 'way'
- }));
+ graph.parentRelations(way).forEach(function(relation) {
+ if (relation.isRestriction()) {
+ var via = relation.memberByRole('via');
+ if (via && newWay.contains(via.id)) {
+ graph = iD.actions.UpdateRelationMember(
+ relation.id,
+ {id: newWay.id},
+ relation.memberById(way.id).index
+ )(graph);
}
+ } else {
+ var role = relation.memberById(way.id).role,
+ last = newWay.last(),
+ i = relation.memberById(way.id).index,
+ j;
+
+ for (j = 0; j < relation.members.length; j++) {
+ if (relation.members[j].type === 'way' && graph.entity(relation.members[j].id).contains(last)) {
+ break;
+ }
+ }
+
+ graph = iD.actions.AddRelationMember(
+ relation.id,
+ {id: newWay.id, type: 'way', role: role},
+ i <= j ? i + 1 : i
+ )(graph);
}
});
diff --git a/js/id/actions/update_relation_member.js b/js/id/actions/update_relation_member.js
index 67a45b6ab..29eb79afe 100644
--- a/js/id/actions/update_relation_member.js
+++ b/js/id/actions/update_relation_member.js
@@ -1,4 +1,4 @@
-iD.actions.UpdateRelationMember = function(relationId, index, properties) {
+iD.actions.UpdateRelationMember = function(relationId, properties, index) {
return function(graph) {
var relation = graph.entity(relationId),
members = relation.members.slice();
diff --git a/js/id/graph/graph.js b/js/id/graph/graph.js
index 74caf7ceb..0d533d461 100644
--- a/js/id/graph/graph.js
+++ b/js/id/graph/graph.js
@@ -136,13 +136,20 @@ iD.Graph.prototype = {
entity = this.entities[id];
oldentity = graph.entities[id];
if (entity !== oldentity) {
- if (entity && entity.type === 'way') {
- result = oldentity ?
- result
+
+ if (entity && entity.type === 'way' &&
+ oldentity && oldentity.type === 'way') {
+ result = result
.concat(_.difference(entity.nodes, oldentity.nodes))
.concat(_.difference(oldentity.nodes, entity.nodes))
- : result.concat(entity.nodes);
+
+ } else if (entity && entity.type === 'way') {
+ result = result.concat(entity.nodes);
+
+ } else if (oldentity && oldentity.type === 'way') {
+ result = result.concat(oldentity.nodes);
}
+
result.push(id);
}
}
diff --git a/js/id/graph/history.js b/js/id/graph/history.js
index e31fa5ef9..3d027d042 100644
--- a/js/id/graph/history.js
+++ b/js/id/graph/history.js
@@ -109,6 +109,16 @@ iD.History = function() {
};
},
+ hasChanges: function() {
+ return !!this.numChanges();
+ },
+
+ numChanges: function() {
+ return d3.sum(d3.values(this.changes()).map(function(c) {
+ return c.length;
+ }));
+ },
+
imagery_used: function(source) {
if (source) imagery_used = source;
else return _.without(
diff --git a/js/id/graph/relation.js b/js/id/graph/relation.js
index 7d8a9aa89..dc298ecbd 100644
--- a/js/id/graph/relation.js
+++ b/js/id/graph/relation.js
@@ -18,6 +18,30 @@ iD.Relation = iD.Entity.extend({
return 'relation';
},
+ // Return the first member with the given role. A copy of the member object
+ // is returned, extended with an 'index' property whose value is the member index.
+ memberByRole: function(role) {
+ for (var i = 0; i < this.members.length; i++) {
+ if (this.members[i].role === role) {
+ return _.extend({}, this.members[i], {index: i});
+ }
+ }
+ },
+
+ // Return the first member with the given id. A copy of the member object
+ // is returned, extended with an 'index' property whose value is the member index.
+ memberById: function(id) {
+ for (var i = 0; i < this.members.length; i++) {
+ if (this.members[i].id === id) {
+ return _.extend({}, this.members[i], {index: i});
+ }
+ }
+ },
+
+ isRestriction: function() {
+ return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
+ },
+
// Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
// where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
//
diff --git a/js/id/graph/way.js b/js/id/graph/way.js
index 305f12051..9efd4fe6c 100644
--- a/js/id/graph/way.js
+++ b/js/id/graph/way.js
@@ -14,12 +14,24 @@ iD.Way = iD.Entity.extend({
});
},
+ first: function() {
+ return this.nodes[0];
+ },
+
+ last: function() {
+ return this.nodes[this.nodes.length - 1];
+ },
+
+ contains: function(node) {
+ return this.nodes.indexOf(node) >= 0;
+ },
+
isOneWay: function() {
return this.tags.oneway === 'yes';
},
isClosed: function() {
- return this.nodes.length > 0 && this.nodes[this.nodes.length - 1] === this.nodes[0];
+ return this.nodes.length > 0 && this.first() === this.last();
},
// a way is an area if:
diff --git a/js/id/id.js b/js/id/id.js
index afcdfc3e4..4d3948107 100644
--- a/js/id/id.js
+++ b/js/id/id.js
@@ -22,15 +22,19 @@ window.iD = function(container) {
.call(map);
var bar = container.append('div')
- .attr('id', 'bar').attr('class', 'fillL2');
+ .attr('id', 'bar')
+ .attr('class','pad1 fillD');
- var buttons_joined = bar.append('div')
- .attr('class', 'buttons-joined');
+ var limiter = bar.append('div')
+ .attr('class', 'limiter');
+
+ var buttons_joined = limiter.append('div')
+ .attr('class', 'button-wrap joined col4');
var buttons = buttons_joined.selectAll('button.add-button')
.data([iD.modes.Browse(), iD.modes.AddPoint(), iD.modes.AddLine(), iD.modes.AddArea()])
.enter().append('button')
- .attr('class', function (mode) { return mode.title + ' add-button'; })
+ .attr('class', function (mode) { return mode.title + ' add-button col3'; })
.attr('data-original-title', function (mode) { return mode.description; })
.call(bootstrap.tooltip().placement('bottom'))
.on('click', function (mode) { controller.enter(mode); });
@@ -46,7 +50,7 @@ window.iD = function(container) {
}
}
- notice = iD.ui.notice(bar
+ var notice = iD.ui.notice(limiter
.append('div')
.attr('class', 'notice'));
@@ -71,55 +75,41 @@ window.iD = function(container) {
container.classed("mode-" + exited.id, false);
});
- var undo_buttons = bar.append('div')
- .attr('class', 'buttons-joined'),
+ var undo_buttons = limiter.append('div')
+ .attr('class', 'button-wrap joined col1'),
undo_tooltip = bootstrap.tooltip().placement('bottom');
undo_buttons.append('button')
- .attr({ id: 'undo', 'class': 'narrow' })
+ .attr({ id: 'undo', 'class': 'col6' })
.property('disabled', true)
.html("")
.on('click', history.undo)
.call(undo_tooltip);
undo_buttons.append('button')
- .attr({ id: 'redo', 'class': 'narrow' })
+ .attr({ id: 'redo', 'class': 'col6' })
.property('disabled', true)
.html("")
.on('click', history.redo)
.call(undo_tooltip);
- container.append('div')
- .attr('class', 'user-container pad1 fillD about-block')
- .append('div')
- .attr('class', 'hello');
-
- var save_button = bar.append('button')
- .attr('class', 'save action wide')
+ var save_button = limiter.append('div').attr('class','button-wrap col1').append('button')
+ .attr('class', 'save col12')
.call(iD.ui.save().map(map).controller(controller));
history.on('change.warn-unload', function() {
- var changes = history.changes(),
-
- has_changes = !!d3.sum(d3.values(changes).map(function(c) {
- return c.length;
- }));
-
- window.onbeforeunload = has_changes ? function() {
+ window.onbeforeunload = history.hasChanges() ? function() {
return 'You have unsaved changes.';
} : null;
});
- bar.append('div')
- .attr('class', 'messages');
-
var zoom = container.append('div')
.attr('class', 'zoombuttons map-control')
.selectAll('button')
.data([['zoom-in', '+', map.zoomIn, 'Zoom In'], ['zoom-out', '-', map.zoomOut, 'Zoom Out']])
.enter()
.append('button')
- .attr('class', function(d) { return d[0] + ' narrow'; })
+ .attr('class', function(d) { return d[0]; })
.attr('title', function(d) { return d[3]; })
.on('click', function(d) { return d[2](); })
.append('span')
@@ -139,21 +129,27 @@ window.iD = function(container) {
.call(iD.ui.layerswitcher(map));
container.append('div')
- .attr('class', 'inspector-wrap fillL')
- .style('display', 'none');
+ .style('display', 'none')
+ .attr('class', 'inspector-wrap fr col5');
- var about = container.append('div').attr('id', 'attrib-container');
+ var about = container.append('div')
+ .attr('class','col12 about-block fillD pad1')
- about.append('ul')
- .attr('id','about')
- .attr('class','pad1 fillD about-block link-list')
- .html("view code " +
+ about.append('div')
+ .attr('class', 'user-container')
+ .append('div')
+ .attr('class', 'hello');
+
+ var aboutList = about.append('ul')
+ .attr('id','about')
+ .attr('class','link-list');
+
+ aboutList.html("view code " +
"report a bug" +
" imagery provided by bing");
- var contributors = about.append('div')
+ var contributors = aboutList.append('li')
.attr('id', 'user-list')
- .attr('class','about-block fillD pad1');
contributors.append('span')
.attr('class', 'icon nearby icon-pre-text');
contributors.append('span')
@@ -173,12 +169,12 @@ window.iD = function(container) {
}
}
- bar.select('#undo')
+ limiter.select('#undo')
.property('disabled', !undo)
.attr('data-original-title', undo)
.call(undo ? refreshTooltip : undo_tooltip.hide);
- bar.select('#redo')
+ limiter.select('#redo')
.property('disabled', !redo)
.attr('data-original-title', redo)
.call(redo ? refreshTooltip : undo_tooltip.hide);
diff --git a/js/id/modes/browse.js b/js/id/modes/browse.js
index c57b503f5..4b2ea448f 100644
--- a/js/id/modes/browse.js
+++ b/js/id/modes/browse.js
@@ -2,7 +2,7 @@ iD.modes.Browse = function() {
var mode = {
button: 'browse',
id: 'browse',
- title: 'Browse',
+ title: 'Move',
description: 'Pan and zoom the map'
};
diff --git a/js/id/modes/draw_area.js b/js/id/modes/draw_area.js
index cdb966351..196a4de53 100644
--- a/js/id/modes/draw_area.js
+++ b/js/id/modes/draw_area.js
@@ -13,7 +13,7 @@ iD.modes.DrawArea = function(wayId) {
headId = (way.nodes.length == 1) ?
way.nodes[0] :
way.nodes[way.nodes.length - 2],
- tailId = _.first(way.nodes),
+ tailId = way.first(),
node = iD.Node({loc: map.mouseCoordinates()});
map.dblclickEnable(false)
diff --git a/js/id/modes/draw_line.js b/js/id/modes/draw_line.js
index 68130d7b8..72a85ae41 100644
--- a/js/id/modes/draw_line.js
+++ b/js/id/modes/draw_line.js
@@ -12,8 +12,8 @@ iD.modes.DrawLine = function(wayId, direction) {
way = history.graph().entity(wayId),
node = iD.Node({loc: map.mouseCoordinates()}),
index = (direction === 'forward') ? undefined : 0,
- headId = (direction === 'forward') ? _.last(way.nodes) : _.first(way.nodes),
- tailId = (direction === 'forward') ? _.first(way.nodes) : _.last(way.nodes);
+ headId = (direction === 'forward') ? way.last() : way.first(),
+ tailId = (direction === 'forward') ? way.first() : way.last();
iD.behavior.Hover()(surface);
diff --git a/js/id/modes/select.js b/js/id/modes/select.js
index 62b309e29..8d59fbe43 100644
--- a/js/id/modes/select.js
+++ b/js/id/modes/select.js
@@ -75,7 +75,7 @@ iD.modes.Select = function (entity) {
}).on('splitWay', function(d) {
mode.history.perform(
iD.actions.SplitWay(d.id),
- 'split a way on a node');
+ 'split a way');
}).on('remove', function() {
remove();
diff --git a/js/id/renderer/map.js b/js/id/renderer/map.js
index 1ffb5cbb9..ede0e54bb 100644
--- a/js/id/renderer/map.js
+++ b/js/id/renderer/map.js
@@ -45,7 +45,7 @@ iD.Map = function() {
if (d3.event.button == 2) {
d3.event.stopPropagation();
}
- })
+ }, true)
.call(iD.svg.Surface());
@@ -237,10 +237,7 @@ iD.Map = function() {
map.size = function(_) {
if (!arguments.length) return dimensions;
dimensions = _;
- surface
- .size(dimensions)
- .selectAll('#clip-rect')
- .size(dimensions);
+ surface.size(dimensions);
background.size(dimensions);
return redraw();
};
diff --git a/js/id/svg/lines.js b/js/id/svg/lines.js
index a0e951591..3ae499b20 100644
--- a/js/id/svg/lines.js
+++ b/js/id/svg/lines.js
@@ -76,10 +76,12 @@ iD.svg.Lines = function(projection) {
var lineString = iD.svg.LineString(projection);
- var casing = surface.select('.layer-casing'),
+ var shadow = surface.select('.layer-shadow'),
+ casing = surface.select('.layer-casing'),
stroke = surface.select('.layer-stroke'),
defs = surface.select('defs'),
text = surface.select('.layer-text'),
+ shadows = drawPaths(shadow, lines, filter, 'way line shadow', lineString, 'shadow-'),
casings = drawPaths(casing, lines, filter, 'way line casing', lineString, 'casing-'),
strokes = drawPaths(stroke, lines, filter, 'way line stroke', lineString, 'stroke-');
diff --git a/js/id/svg/member_classes.js b/js/id/svg/member_classes.js
index b675288c3..d5745a466 100644
--- a/js/id/svg/member_classes.js
+++ b/js/id/svg/member_classes.js
@@ -19,7 +19,7 @@ iD.svg.MemberClasses = function(graph) {
relations.forEach(function (relation) {
classes += ' member-type-' + relation.tags.type;
- classes += ' member-role-' + _.find(relation.members, function (member) { return member.id == d.id; }).role;
+ classes += ' member-role-' + relation.memberById(d.id).role;
});
classes = classes.trim();
diff --git a/js/id/svg/midpoints.js b/js/id/svg/midpoints.js
index 321e75c8e..7c7c7a0c3 100644
--- a/js/id/svg/midpoints.js
+++ b/js/id/svg/midpoints.js
@@ -22,17 +22,25 @@ iD.svg.Midpoints = function(projection) {
}
}
- var handles = surface.select('.layer-hit').selectAll('circle.midpoint')
+ var groups = surface.select('.layer-hit').selectAll('g.midpoint')
.filter(filter)
.data(midpoints, function (d) { return [d.way, d.index].join(","); });
- handles.enter()
- .append('circle')
- .attr({ r: 3, 'class': 'midpoint' });
+ var group = groups.enter()
+ .insert('g', ':first-child')
+ .attr('class', 'midpoint');
- handles.attr('transform', iD.svg.PointTransform(projection));
+ group.append('circle')
+ .attr('r', 7)
+ .attr('class', 'shadow');
- handles.exit()
+ group.append('circle')
+ .attr('r', 3)
+ .attr('class', 'fill');
+
+ groups.attr('transform', iD.svg.PointTransform(projection));
+
+ groups.exit()
.remove();
};
};
diff --git a/js/id/svg/surface.js b/js/id/svg/surface.js
index 0da1cc4ac..5443db8c7 100644
--- a/js/id/svg/surface.js
+++ b/js/id/svg/surface.js
@@ -1,17 +1,9 @@
iD.svg.Surface = function() {
return function drawSurface(selection) {
- selection.append('defs')
- .append('clipPath')
- .attr('id', 'clip')
- .append('rect')
- .attr('id', 'clip-rect')
- .attr({ x: 0, y: 0 });
+ selection.append('defs');
- var clip = selection.append('g')
- .attr('clip-path', 'url(#clip)');
-
- var layers = clip.selectAll('.layer')
- .data(['fill', 'casing', 'stroke', 'text', 'hit', 'label']);
+ var layers = selection.selectAll('.layer')
+ .data(['shadow', 'fill', 'casing', 'stroke', 'text', 'hit', 'label']);
layers.enter().append('g')
.attr('class', function(d) { return 'layer layer-' + d; });
diff --git a/js/id/svg/tag_classes.js b/js/id/svg/tag_classes.js
index a7660e1f5..5ce585add 100644
--- a/js/id/svg/tag_classes.js
+++ b/js/id/svg/tag_classes.js
@@ -1,8 +1,8 @@
iD.svg.TagClasses = function() {
var keys = iD.util.trueObj([
- 'highway', 'railway', 'motorway', 'amenity', 'natural',
- 'landuse', 'building', 'oneway', 'bridge', 'boundary',
- 'leisure'
+ 'highway', 'railway', 'waterway', 'power', 'motorway', 'amenity',
+ 'natural', 'landuse', 'building', 'oneway', 'bridge', 'boundary',
+ 'leisure', 'construction'
]), tagClassRe = /^tag-/;
return function tagClassesSelection(selection) {
diff --git a/js/id/svg/vertices.js b/js/id/svg/vertices.js
index ce81dface..4a975d38b 100644
--- a/js/id/svg/vertices.js
+++ b/js/id/svg/vertices.js
@@ -22,12 +22,16 @@ iD.svg.Vertices = function(projection) {
.attr('class', 'node vertex');
group.append('circle')
- .attr('class', 'stroke')
- .attr('r', 6);
+ .attr('r', 10)
+ .attr('class', 'shadow');
group.append('circle')
- .attr('class', 'fill')
- .attr('r', 4);
+ .attr('r', 6)
+ .attr('class', 'stroke');
+
+ group.append('circle')
+ .attr('r', 3)
+ .attr('class', 'fill');
groups.attr('transform', iD.svg.PointTransform(projection))
.call(iD.svg.TagClasses())
diff --git a/js/id/ui/commit.js b/js/id/ui/commit.js
index 06d072275..b63150ba3 100644
--- a/js/id/ui/commit.js
+++ b/js/id/ui/commit.js
@@ -28,7 +28,7 @@ iD.ui.commit = function() {
var changes = selection.datum(),
connection = changes.connection,
user = connection.user(),
- header = selection.append('div').attr('class', 'header modal-section'),
+ header = selection.append('div').attr('class', 'header modal-section fillL'),
body = selection.append('div').attr('class', 'body');
@@ -54,40 +54,44 @@ iD.ui.commit = function() {
.append('div')
.text(user.display_name);
- header.append('h2').text('Upload Changes to OpenStreetMap');
+ header.append('h2').text('Save Changes');
header.append('p').text('The changes you upload will be visible on all maps that use OpenStreetMap data.');
- var comment_section = body.append('div').attr('class','modal-section');
+ // Comment Box
+ var comment_section = body.append('div').attr('class','modal-section fillD');
comment_section.append('textarea')
.attr('class', 'changeset-comment')
.attr('placeholder', 'Brief Description of your contributions');
+ // Confirm / Cancel Buttons
var buttonwrap = comment_section.append('div')
- .attr('class', 'buttons');
+ .attr('class', 'buttons cf')
+ .append('div')
+ .attr('class', 'button-wrap joined col4');
- var savebutton = buttonwrap.append('button')
- .attr('class', 'action wide')
- .on('click.save', function() {
- event.save({
- comment: d3.select('textarea.changeset-comment').node().value
+ var savebutton = buttonwrap
+ .append('button')
+ .attr('class', 'save action col6 button')
+ .on('click.save', function() {
+ event.save({
+ comment: d3.select('textarea.changeset-comment').node().value
+ });
});
- });
- savebutton.append('span').attr('class','icon save icon-pre-text');
- savebutton.append('span').attr('class','label').text('Save');
+ savebutton.append('span').attr('class','label').text('Save');
var cancelbutton = buttonwrap.append('button')
- .attr('class', 'cancel wide')
- .on('click.cancel', function() {
- event.cancel();
- });
- cancelbutton.append('span').attr('class','icon close icon-pre-text');
- cancelbutton.append('span').attr('class','label').text('Cancel');
+ .attr('class', 'cancel col6 button')
+ .on('click.cancel', function() {
+ event.cancel();
+ });
+ cancelbutton.append('span').attr('class','icon close icon-pre-text');
+ cancelbutton.append('span').attr('class','label').text('Cancel');
var warnings = body.selectAll('div.warning-section')
.data(iD.validate(changes))
.enter()
- .append('div').attr('class', 'modal-section warning-section');
+ .append('div').attr('class', 'modal-section warning-section fillL');
warnings.append('h3')
.text('Warnings');
diff --git a/js/id/ui/confirm.js b/js/id/ui/confirm.js
index 11515996e..02133406b 100644
--- a/js/id/ui/confirm.js
+++ b/js/id/ui/confirm.js
@@ -2,12 +2,12 @@ iD.ui.confirm = function() {
var modal = iD.ui.modal();
modal.select('.modal').classed('modal-alert', true);
modal.select('.content')
- .classed('modal-section', true)
+ .attr('class','modal-section fillD')
.append('div')
.attr('class', 'description');
var nochanges = modal.select('.content')
.append('button')
- .attr('class','wide action centered')
+ .attr('class','action centered')
.on('click.confirm', function() {
modal.remove();
});
diff --git a/js/id/ui/flash.js b/js/id/ui/flash.js
index 7b3b00628..4ce6a3b0a 100644
--- a/js/id/ui/flash.js
+++ b/js/id/ui/flash.js
@@ -10,7 +10,7 @@ iD.ui.flash = function() {
modal.on('click.flash', function() { modal.remove(); });
- d3.timer(function() {
+ setTimeout(function() {
modal.remove();
return true;
}, 1000);
diff --git a/js/id/ui/geocoder.js b/js/id/ui/geocoder.js
index 4bd8c0629..ba3e0db2f 100644
--- a/js/id/ui/geocoder.js
+++ b/js/id/ui/geocoder.js
@@ -41,14 +41,13 @@ iD.ui.geocoder = function() {
}
var button = selection.append('button')
- .attr('class', 'narrow')
.attr('title', 'Find A Location')
.html('')
.on('click', toggle);
var gcForm = selection.append('form');
- gcForm.attr('class','content map-overlay hide')
+ gcForm.attr('class','content fillD map-overlay hide')
.append('input')
.attr({ type: 'text', placeholder: 'find a place' })
.on('keydown', keydown);
diff --git a/js/id/ui/geolocate.js b/js/id/ui/geolocate.js
index 906c031c4..803b0d49d 100644
--- a/js/id/ui/geolocate.js
+++ b/js/id/ui/geolocate.js
@@ -10,13 +10,13 @@ iD.ui.geolocate = function(map) {
selection
.attr('class', 'geolocate-control map-control')
.append('button')
- .attr('class', 'narrow')
.attr('title', 'Show My Location')
- .text('G')
.on('click', function() {
navigator.geolocation.getCurrentPosition(
success, error);
- });
+ })
+ .append('span')
+ .attr('class','icon geolocate');
};
};
diff --git a/js/id/ui/inspector.js b/js/id/ui/inspector.js
index 600538e4c..850fe84c0 100644
--- a/js/id/ui/inspector.js
+++ b/js/id/ui/inspector.js
@@ -7,18 +7,14 @@ iD.ui.inspector = function() {
function inspector(selection) {
var entity = selection.datum();
- selection.html('').append('button')
- .attr('class', 'narrow close')
- .html("")
- .on('click', function() {
- event.close(entity);
- });
+ var inspector = selection.append('div')
+ .attr('class','inspector content');
- selection.append('div')
- .attr('class', 'head inspector-inner')
+ inspector.append('div')
+ .attr('class', 'head inspector-inner fillL')
.call(drawHead);
- var inspectorbody = selection.append('div')
+ var inspectorbody = inspector.append('div')
.attr('class', 'inspector-body');
var inspectorwrap = inspectorbody.append('div')
@@ -43,7 +39,7 @@ iD.ui.inspector = function() {
drawTags(entity.tags);
inspectorbody.append('div')
- .attr('class', 'inspector-buttons')
+ .attr('class', 'inspector-buttons pad1 fillD')
.call(drawButtons);
}
@@ -57,37 +53,45 @@ iD.ui.inspector = function() {
h2.append('span')
.text(entity.friendlyName());
-
- selection.append('a')
- .attr('href', 'http://www.openstreetmap.org/browse/' + entity.type + '/' + entity.osmId())
- .attr('target', '_blank')
- .text('View on OSM');
-
- if (entity.type === 'way') {
- selection.append('a')
- .attr('href', '#')
- .text('Reverse Direction')
- .on('click', function() { event.changeWayDirection(entity); });
- }
-
- if (entity.geometry() === 'vertex') {
- selection.append('a')
- .attr('href', '#')
- .text('Split Way')
- .on('click', function() { event.splitWay(entity); });
- }
}
function drawButtons(selection) {
- selection.append('button')
- .attr('class', 'apply wide action')
- .html("Close")
- .on('click', apply);
+ var entity = selection.datum();
+ var inspectorButtonWrap = selection.append('div')
+ .attr('class','button-wrap joined fl');
+ var inspectorButton1 = inspectorButtonWrap.append('button')
+ .attr('class', 'apply col6 action')
+ .on('click', apply);
+
+ inspectorButton1.append('span').attr('class','icon icon-pre-text apply');
+ inspectorButton1.append('span').attr('class','label').text('Okay');
+
+ var inspectorButton2 = inspectorButtonWrap.append('button')
+ .attr('class', 'delete col6 action')
+ .on('click', function(entity) { event.remove(entity); });
+
+ inspectorButton2.append('span').attr('class','icon icon-pre-text delete');
+ inspectorButton2.append('span').attr('class','label').text('Delete');
+
+ var minorButtons = selection.append('div').attr('class','minor-buttons fl');
+
+ minorButtons.append('a')
+ .attr('href', 'http://www.openstreetmap.org/browse/' + entity.type + '/' + entity.osmId())
+ .attr('target', '_blank')
+ .text('View on OSM');
+ if (entity.type === 'way') {
+ minorButtons.append('a')
+ .attr('href', '#')
+ .text('Reverse Direction')
+ .on('click', function() { event.changeWayDirection(entity); });
+ }
+ if (entity.geometry() === 'vertex') {
+ minorButtons.append('a')
+ .attr('href', '#')
+ .text('Split Way')
+ .on('click', function() { event.splitWay(entity); });
+ }
- selection.append('button')
- .attr('class', 'delete wide action')
- .html("Delete")
- .on('click', function(entity) { event.remove(entity); });
}
function drawTags(tags) {
@@ -139,57 +143,50 @@ iD.ui.inspector = function() {
var helpBtn = row.append('button')
.attr('tabindex', -1)
.attr('class', 'tag-help minor')
- .append('a')
- .attr('tabindex', -1)
- .attr('target', '_blank')
- .on('click', function(d) {
- var params = _.extend({}, d, {
- geometry: entity.geometry()
- });
- if (d.key && d.value) {
- taginfo.docs(params, function(err, docs) {
- var en = _.find(docs, function(d) {
- return d.lang == 'en';
- });
- if (en) {
- var types = [];
- if (en.on_area) types.push('area');
- if (en.on_node) types.push('point');
- if (en.on_way) types.push('line');
- en.types = types;
- iD.ui.modal()
- .select('.content')
- .datum(en)
- .call(iD.ui.tagReference);
- } else {
- iD.ui.flash()
- .select('.content')
- .text('This is no documentation available for this tag combination');
- }
- });
- } else if (d.key) {
- taginfo.values(params, function(err, values) {
- if (values.data.length) {
- iD.ui.modal()
- .select('.content')
- .datum({
- data: values.data,
- title: 'Key:' + params.key,
- geometry: params.geometry
- })
- .call(iD.keyReference);
- } else {
- iD.ui.flash()
- .select('.content')
- .text('This is no documentation available for this key');
- }
- });
- }
- d3.event.preventDefault();
- })
- .attr('href', function(d) {
- return 'http://taginfo.openstreetmap.org/keys/' + d.key;
+ .on('click', function(d) {
+ var params = _.extend({}, d, {
+ geometry: entity.geometry()
});
+ if (d.key && d.value) {
+ taginfo.docs(params, function(err, docs) {
+ var en = _.find(docs, function(d) {
+ return d.lang == 'en';
+ });
+ if (en) {
+ var types = [];
+ if (en.on_area) types.push('area');
+ if (en.on_node) types.push('point');
+ if (en.on_way) types.push('line');
+ en.types = types;
+ iD.ui.modal()
+ .select('.content')
+ .datum(en)
+ .call(iD.ui.tagReference);
+ } else {
+ iD.ui.flash()
+ .select('.content')
+ .text('This is no documentation available for this tag combination');
+ }
+ });
+ } else if (d.key) {
+ taginfo.values(params, function(err, values) {
+ if (values.data.length) {
+ iD.ui.modal()
+ .select('.content')
+ .datum({
+ data: values.data,
+ title: 'Key:' + params.key,
+ geometry: params.geometry
+ })
+ .call(iD.keyReference);
+ } else {
+ iD.ui.flash()
+ .select('.content')
+ .text('This is no documentation available for this key');
+ }
+ });
+ }
+ });
helpBtn.append('span')
.attr('class', 'icon inspect');
diff --git a/js/id/ui/key_reference.js b/js/id/ui/key_reference.js
index 5810018f1..1c1515150 100644
--- a/js/id/ui/key_reference.js
+++ b/js/id/ui/key_reference.js
@@ -4,10 +4,10 @@ iD.ui.keyReference = function(selection) {
var selection = d3.select(this),
data = selection.datum(),
header = selection.append('div')
- .attr('class','modal-section')
+ .attr('class','modal-section fillL')
.append('h2'),
body = selection.append('div')
- .attr('class', 'modal-section');
+ .attr('class', 'modal-section fillL2');
header.append('span').attr('class', 'icon big icon-pre-text big-' + data.geometry);
header.append('span').text(data.title);
diff --git a/js/id/ui/layerswitcher.js b/js/id/ui/layerswitcher.js
index a2acad1b5..1d1dc4f71 100644
--- a/js/id/ui/layerswitcher.js
+++ b/js/id/ui/layerswitcher.js
@@ -29,11 +29,11 @@ iD.ui.layerswitcher = function(map) {
function layerswitcher(selection) {
var content = selection
- .append('div').attr('class', 'content map-overlay hide');
+ .append('div').attr('class', 'content fillD map-overlay hide');
var button = selection
.append('button')
- .attr('class', 'narrow')
+ .attr('class', 'fillD')
.attr('title', 'Layer Settings')
.html("")
.on('click.layerswitcher-toggle', toggle);
@@ -56,7 +56,7 @@ iD.ui.layerswitcher = function(map) {
var opa = content
.append('div')
- .attr('class', 'opacity-options-wrapper fillL2');
+ .attr('class', 'opacity-options-wrapper');
opa.append('h4').text('Layers');
@@ -102,7 +102,7 @@ iD.ui.layerswitcher = function(map) {
content
.append('ul')
- .attr('class', 'toggle-list')
+ .attr('class', 'toggle-list fillL')
.selectAll('a.layer')
.data(sources)
.enter()
@@ -135,7 +135,7 @@ iD.ui.layerswitcher = function(map) {
var adjustments = content
.append('div')
- .attr('class', 'adjustments');
+ .attr('class', 'adjustments pad1');
var directions = [
['←', [-1, 0]],
diff --git a/js/id/ui/loading.js b/js/id/ui/loading.js
index d5bd97625..6a98a917a 100644
--- a/js/id/ui/loading.js
+++ b/js/id/ui/loading.js
@@ -3,7 +3,7 @@ iD.ui.loading = function(message) {
var loadertext = modal.select('.content')
.classed('loading-modal', true)
- .append('div').classed('modal-section',true);
+ .append('div').attr('class','modal-section fillL');
loadertext.append('img').attr('class','loader').attr('src', '/img/loader.gif');
loadertext.append('h3').text(message || '');
diff --git a/js/id/ui/save.js b/js/id/ui/save.js
index 6bf8419c3..afaab5023 100644
--- a/js/id/ui/save.js
+++ b/js/id/ui/save.js
@@ -7,7 +7,7 @@ iD.ui.save = function() {
var history = map.history(),
connection = map.connection();
- selection.html("Save")
+ selection.html("Save")
.attr('title', 'Save changes to OpenStreetMap, making them visible to other users')
.property('disabled', true)
.call(bootstrap.tooltip()
@@ -22,7 +22,7 @@ iD.ui.save = function() {
history.reset();
map.flush().redraw();
if (err) {
- var desc = iD.confirm()
+ var desc = iD.ui.confirm()
.select('.description');
desc.append('h2')
.text('An error occurred while trying to save');
@@ -42,12 +42,8 @@ iD.ui.save = function() {
}
});
}
- var changes = history.changes();
- var has_changes = d3.sum(d3.values(changes).map(function(c) {
- return c.length;
- })) > 0;
- if (has_changes) {
+ if (history.hasChanges()) {
connection.authenticate(function(err) {
var modal = iD.ui.modal();
var changes = history.changes();
@@ -68,7 +64,7 @@ iD.ui.save = function() {
.on('save', commit));
});
} else {
- iD.confirm().select('.description')
+ iD.ui.confirm().select('.description')
.append('h3').text('You don\'t have any changes to save.');
}
});
@@ -77,16 +73,13 @@ iD.ui.save = function() {
.attr('class', 'count');
history.on('change.save-button', function() {
- var changes = history.changes(),
- num_changes = d3.sum(d3.values(changes).map(function(c) {
- return c.length;
- }));
+ var hasChanges = history.hasChanges();
selection
- .property('disabled', num_changes === 0)
- .classed('has-count', num_changes > 0)
+ .property('disabled', !hasChanges)
+ .classed('has-count', hasChanges)
.select('span.count')
- .text(num_changes);
+ .text(history.numChanges());
});
}
diff --git a/js/id/ui/success.js b/js/id/ui/success.js
index cd4181bbe..d135f7d80 100644
--- a/js/id/ui/success.js
+++ b/js/id/ui/success.js
@@ -3,10 +3,10 @@ iD.ui.success = function() {
function success(selection) {
var changeset = selection.datum(),
- header = selection.append('div').attr('class', 'header modal-section'),
+ header = selection.append('div').attr('class', 'header fillL modal-section'),
body = selection.append('div').attr('class', 'body');
- var section = body.append('div').attr('class','modal-section');
+ var section = body.append('div').attr('class','modal-section fillD');
header.append('h2').text('You Just Edited OpenStreetMap!');
header.append('p').text('You just improved the world\'s best free map');
@@ -27,16 +27,16 @@ iD.ui.success = function() {
.text('Tweet: ' + message);
var buttonwrap = section.append('div')
- .attr('class', 'buttons');
+ .attr('class', 'buttons cf');
var okbutton = buttonwrap.append('button')
- .attr('class', 'action wide')
+ .attr('class', 'action col2')
.on('click.save', function() {
event.cancel();
});
okbutton.append('span').attr('class','icon apply icon-pre-text');
- okbutton.append('span').attr('class','label').text('OK');
+ okbutton.append('span').attr('class','label').text('Okay');
}
return d3.rebind(success, event, 'on');
diff --git a/js/id/ui/tag_reference.js b/js/id/ui/tag_reference.js
index 55e20d8cb..eb1ee84bd 100644
--- a/js/id/ui/tag_reference.js
+++ b/js/id/ui/tag_reference.js
@@ -3,7 +3,7 @@ iD.ui.tagReference = function(selection) {
function g(x) { return function(d) { return d[x]; }; }
var selection = d3.select(this);
var header = selection.append('div')
- .attr('class','modal-section')
+ .attr('class','modal-section fillL header')
.append('h2');
header.selectAll('span.icon')
@@ -20,7 +20,7 @@ iD.ui.tagReference = function(selection) {
.text(g('title'));
referenceBody = selection.append('div')
- .attr('class','modal-section');
+ .attr('class','modal-section fillL2');
referenceBody
.append('h5')
diff --git a/js/id/ui/userpanel.js b/js/id/ui/userpanel.js
index bab5e28d9..57f368d65 100644
--- a/js/id/ui/userpanel.js
+++ b/js/id/ui/userpanel.js
@@ -7,20 +7,26 @@ iD.ui.userpanel = function(connection) {
if (connection.authenticated()) {
selection.style('display', 'block');
connection.userDetails(function(user_details) {
- if (user_details.image_url) {
- selection.append('img')
- .attr('class', 'icon icon-pre-text')
- .attr('src', user_details.image_url);
- } else {
- selection.append('span')
- .attr('class','icon avatar icon-pre-text');
- }
- selection.append('span')
- .append('a')
+
+ // Link
+ var userLink = selection.append('a')
.attr('href', connection.url() + '/user/' +
user_details.display_name)
.attr('target', '_blank')
- .text(user_details.display_name);
+
+ // Add thumbnail or dont
+ if (user_details.image_url) {
+ userLink.append('img')
+ .attr('class', 'icon icon-pre-text')
+ .attr('src', user_details.image_url);
+ } else {
+ userLink.append('span')
+ .attr('class','icon avatar icon-pre-text');
+ }
+
+ // Add user name
+ userLink.append('span').attr('class','label').text(user_details.display_name);
+
selection
.append('a')
.attr('class', 'logout')
diff --git a/test/index.html b/test/index.html
index 0777751d5..425258d20 100644
--- a/test/index.html
+++ b/test/index.html
@@ -66,6 +66,7 @@
+
@@ -124,6 +125,7 @@
+
diff --git a/test/index_packaged.html b/test/index_packaged.html
index 630ed1088..8def4c0da 100644
--- a/test/index_packaged.html
+++ b/test/index_packaged.html
@@ -31,6 +31,7 @@
+
diff --git a/test/rendering.html b/test/rendering.html
new file mode 100644
index 000000000..ebefeaa4a
--- /dev/null
+++ b/test/rendering.html
@@ -0,0 +1,127 @@
+
+
+
+
+ Rendering Tests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | z16 | z17 |
+ | Base | Hover | Selected | Base | Hover | Selected |
+
+
+
+
+
+
+
+
diff --git a/test/spec/actions/add_relation_member.js b/test/spec/actions/add_relation_member.js
new file mode 100644
index 000000000..aeae8e353
--- /dev/null
+++ b/test/spec/actions/add_relation_member.js
@@ -0,0 +1,37 @@
+describe("iD.actions.AddRelationMember", function () {
+ it("adds a member at the end of the relation", function () {
+ var relation = iD.Relation(),
+ graph = iD.Graph([relation]);
+
+ graph = iD.actions.AddRelationMember(relation.id, {id: '1'})(graph);
+
+ expect(graph.entity(relation.id).members).to.eql([{id: '1'}]);
+ });
+
+ it("adds a member at index 0", function () {
+ var relation = iD.Relation({members: [{id: '1'}]}),
+ graph = iD.Graph([relation]);
+
+ graph = iD.actions.AddRelationMember(relation.id, {id: '2'}, 0)(graph);
+
+ expect(graph.entity(relation.id).members).to.eql([{id: '2'}, {id: '1'}]);
+ });
+
+ it("adds a member at a positive index", function () {
+ var relation = iD.Relation({members: [{id: '1'}, {id: '3'}]}),
+ graph = iD.Graph([relation]);
+
+ graph = iD.actions.AddRelationMember(relation.id, {id: '2'}, 1)(graph);
+
+ expect(graph.entity(relation.id).members).to.eql([{id: '1'}, {id: '2'}, {id: '3'}]);
+ });
+
+ it("adds a member at a negative index", function () {
+ var relation = iD.Relation({members: [{id: '1'}, {id: '3'}]}),
+ graph = iD.Graph([relation]);
+
+ graph = iD.actions.AddRelationMember(relation.id, {id: '2'}, -1)(graph);
+
+ expect(graph.entity(relation.id).members).to.eql([{id: '1'}, {id: '2'}, {id: '3'}]);
+ });
+});
diff --git a/test/spec/actions/split_way.js b/test/spec/actions/split_way.js
index 6a4edc187..e83d5ee1a 100644
--- a/test/spec/actions/split_way.js
+++ b/test/spec/actions/split_way.js
@@ -8,55 +8,206 @@ describe("iD.actions.SplitWay", function () {
// Expected result:
// a ---- b ==== c
//
- var a = iD.Node(),
- b = iD.Node(),
- c = iD.Node(),
- way = iD.Way({nodes: [a.id, b.id, c.id]}),
- graph = iD.Graph([a, b, c, way]);
+ var graph = iD.Graph({
+ 'a': iD.Node({id: 'a'}),
+ 'b': iD.Node({id: 'b'}),
+ 'c': iD.Node({id: 'c'}),
+ '-': iD.Way({id: '-', nodes: ['a', 'b', 'c']})
+ });
- graph = iD.actions.SplitWay(b.id)(graph);
+ graph = iD.actions.SplitWay('b', '=')(graph);
- var waysA = graph.parentWays(a),
- waysB = graph.parentWays(b),
- waysC = graph.parentWays(c);
-
- expect(waysA).to.have.length(1);
- expect(waysB).to.have.length(2);
- expect(waysC).to.have.length(1);
-
- expect(waysA[0]).to.equal(waysB[0]);
- expect(waysB[1]).to.equal(waysC[0]);
+ expect(graph.entity('-').nodes).to.eql(['a', 'b']);
+ expect(graph.entity('=').nodes).to.eql(['b', 'c']);
});
- it("moves restriction relations to the new way", function () {
+ it("copies tags to the new way", function () {
+ var tags = {highway: 'residential'},
+ graph = iD.Graph({
+ 'a': iD.Node({id: 'a'}),
+ 'b': iD.Node({id: 'b'}),
+ 'c': iD.Node({id: 'c'}),
+ '-': iD.Way({id: '-', nodes: ['a', 'b', 'c'], tags: tags})
+ });
+
+ graph = iD.actions.SplitWay('b', '=')(graph);
+
+ // Immutable tags => should be shared by identity.
+ expect(graph.entity('-').tags).to.equal(tags);
+ expect(graph.entity('=').tags).to.equal(tags);
+ });
+
+ it("adds the new way to parent relations (no connections)", function () {
// Situation:
- // a ==== b ==== c ---- d
- // A restriction from ==== to ---- via c.
+ // a ---- b ---- c
+ // Relation: [----]
//
// Split at b.
//
// Expected result:
- // a ==== b ≠≠≠≠ c ---- d
- // A restriction from ≠≠≠≠ to ---- via c.
+ // a ---- b ==== c
+ // Relation: [----, ====]
//
- var a = iD.Node(),
- b = iD.Node(),
- c = iD.Node(),
- d = iD.Node(),
- from = iD.Way({nodes: [a.id, b.id, c.id]}),
- to = iD.Way({nodes: [c.id, d.id]}),
- restriction = iD.Relation({tags: {type: 'restriction'}, members: [
- { role: 'from', id: from.id },
- { role: 'to', id: to.id },
- { role: 'via', id: c.id }]}),
- graph = iD.Graph([a, b, c, d, from, to, restriction]);
+ var graph = iD.Graph({
+ 'a': iD.Node({id: 'a'}),
+ 'b': iD.Node({id: 'b'}),
+ 'c': iD.Node({id: 'c'}),
+ '-': iD.Way({id: '-', nodes: ['a', 'b', 'c']}),
+ 'r': iD.Relation({id: 'r', members: [{id: '-', type: 'way'}]})
+ });
- graph = iD.actions.SplitWay(b.id)(graph);
+ graph = iD.actions.SplitWay('b', '=')(graph);
- restriction = graph.entity(restriction.id);
+ expect(_.pluck(graph.entity('r').members, 'id')).to.eql(['-', '=']);
+ });
- expect(restriction.members[0]).not.to.eql({ role: 'from', id: from.id });
- expect(restriction.members[1]).to.eql({ role: 'to', id: to.id });
- expect(restriction.members[2]).to.eql({ role: 'via', id: c.id });
+ it("adds the new way to parent relations (forward order)", function () {
+ // Situation:
+ // a ---- b ---- c ~~~~ d
+ // Relation: [----, ~~~~]
+ //
+ // Split at b.
+ //
+ // Expected result:
+ // a ---- b ==== c ~~~~ d
+ // Relation: [----, ====, ~~~~]
+ //
+ var graph = iD.Graph({
+ 'a': iD.Node({id: 'a'}),
+ 'b': iD.Node({id: 'b'}),
+ 'c': iD.Node({id: 'c'}),
+ 'd': iD.Node({id: 'd'}),
+ '-': iD.Way({id: '-', nodes: ['a', 'b', 'c']}),
+ '~': iD.Way({id: '~', nodes: ['c', 'd']}),
+ 'r': iD.Relation({id: 'r', members: [{id: '-', type: 'way'}, {id: '~', type: 'way'}]})
+ });
+
+ graph = iD.actions.SplitWay('b', '=')(graph);
+
+ expect(_.pluck(graph.entity('r').members, 'id')).to.eql(['-', '=', '~']);
+ });
+
+ it("adds the new way to parent relations (reverse order)", function () {
+ // Situation:
+ // a ---- b ---- c ~~~~ d
+ // Relation: [~~~~, ----]
+ //
+ // Split at b.
+ //
+ // Expected result:
+ // a ---- b ==== c ~~~~ d
+ // Relation: [~~~~, ====, ----]
+ //
+ var graph = iD.Graph({
+ 'a': iD.Node({id: 'a'}),
+ 'b': iD.Node({id: 'b'}),
+ 'c': iD.Node({id: 'c'}),
+ 'd': iD.Node({id: 'd'}),
+ '-': iD.Way({id: '-', nodes: ['a', 'b', 'c']}),
+ '~': iD.Way({id: '~', nodes: ['c', 'd']}),
+ 'r': iD.Relation({id: 'r', members: [{id: '~', type: 'way'}, {id: '-', type: 'way'}]})
+ });
+
+ graph = iD.actions.SplitWay('b', '=')(graph);
+
+ expect(_.pluck(graph.entity('r').members, 'id')).to.eql(['~', '=', '-']);
+ });
+
+ ['restriction', 'restriction:bus'].forEach(function (type) {
+ it("updates a restriction's 'from' role", function () {
+ // Situation:
+ // a ----> b ----> c ~~~~ d
+ // A restriction from ---- to ~~~~ via c.
+ //
+ // Split at b.
+ //
+ // Expected result:
+ // a ----> b ====> c ~~~~ d
+ // A restriction from ==== to ~~~~ via c.
+ //
+ var graph = iD.Graph({
+ 'a': iD.Node({id: 'a'}),
+ 'b': iD.Node({id: 'b'}),
+ 'c': iD.Node({id: 'c'}),
+ 'd': iD.Node({id: 'd'}),
+ '-': iD.Way({id: '-', nodes: ['a', 'b', 'c']}),
+ '~': iD.Way({id: '~', nodes: ['c', 'd']}),
+ 'r': iD.Relation({id: 'r', tags: {type: type}, members: [
+ {id: '-', role: 'from'},
+ {id: '~', role: 'to'},
+ {id: 'c', role: 'via'}]})
+ });
+
+ graph = iD.actions.SplitWay('b', '=')(graph);
+
+ expect(graph.entity('r').members).to.eql([
+ {id: '=', role: 'from'},
+ {id: '~', role: 'to'},
+ {id: 'c', role: 'via'}]);
+ });
+
+ it("updates a restriction's 'to' role", function () {
+ // Situation:
+ // a ----> b ----> c ~~~~ d
+ // A restriction from ~~~~ to ---- via c.
+ //
+ // Split at b.
+ //
+ // Expected result:
+ // a ----> b ====> c ~~~~ d
+ // A restriction from ~~~~ to ==== via c.
+ //
+ var graph = iD.Graph({
+ 'a': iD.Node({id: 'a'}),
+ 'b': iD.Node({id: 'b'}),
+ 'c': iD.Node({id: 'c'}),
+ 'd': iD.Node({id: 'd'}),
+ '-': iD.Way({id: '-', nodes: ['a', 'b', 'c']}),
+ '~': iD.Way({id: '~', nodes: ['c', 'd']}),
+ 'r': iD.Relation({id: 'r', tags: {type: type}, members: [
+ {id: '~', role: 'from'},
+ {id: '-', role: 'to'},
+ {id: 'c', role: 'via'}]})
+ });
+
+ graph = iD.actions.SplitWay('b', '=')(graph);
+
+ expect(graph.entity('r').members).to.eql([
+ {id: '~', role: 'from'},
+ {id: '=', role: 'to'},
+ {id: 'c', role: 'via'}]);
+ });
+
+ it("leaves unaffected restrictions unchanged", function () {
+ // Situation:
+ // a <---- b <---- c ~~~~ d
+ // A restriction from ---- to ~~~~ via c.
+ //
+ // Split at b.
+ //
+ // Expected result:
+ // a <==== b <---- c ~~~~ d
+ // A restriction from ---- to ~~~~ via c.
+ //
+ var graph = iD.Graph({
+ 'a': iD.Node({id: 'a'}),
+ 'b': iD.Node({id: 'b'}),
+ 'c': iD.Node({id: 'c'}),
+ 'd': iD.Node({id: 'd'}),
+ '-': iD.Way({id: '-', nodes: ['c', 'b', 'a']}),
+ '~': iD.Way({id: '~', nodes: ['c', 'd']}),
+ 'r': iD.Relation({id: 'r', tags: {type: type}, members: [
+ {id: '-', role: 'from'},
+ {id: '~', role: 'to'},
+ {id: 'c', role: 'via'}]})
+ });
+
+ graph = iD.actions.SplitWay('b', '=')(graph);
+
+ expect(graph.entity('r').members).to.eql([
+ {id: '-', role: 'from'},
+ {id: '~', role: 'to'},
+ {id: 'c', role: 'via'}]);
+ });
});
});
diff --git a/test/spec/actions/update_relation_member.js b/test/spec/actions/update_relation_member.js
index 1878ff923..c85d72b34 100644
--- a/test/spec/actions/update_relation_member.js
+++ b/test/spec/actions/update_relation_member.js
@@ -2,7 +2,7 @@ describe("iD.actions.UpdateRelationMember", function () {
it("updates the properties of the relation member at the specified index", function () {
var node = iD.Node(),
relation = iD.Relation({members: [{id: node.id, role: 'forward'}]}),
- graph = iD.actions.UpdateRelationMember(relation.id, 0, {role: 'backward'})(iD.Graph([node, relation]));
+ graph = iD.actions.UpdateRelationMember(relation.id, {role: 'backward'}, 0)(iD.Graph([node, relation]));
expect(graph.entity(relation.id).members).to.eql([{id: node.id, role: 'backward'}]);
});
});
diff --git a/test/spec/graph/entity.js b/test/spec/graph/entity.js
index e5741104f..3f3a701fe 100644
--- a/test/spec/graph/entity.js
+++ b/test/spec/graph/entity.js
@@ -113,6 +113,22 @@ describe('iD.Entity', function () {
});
});
+ describe("#intersects", function () {
+ it("returns true for a way with a node within the given extent", function () {
+ var node = iD.Node({loc: [0, 0]}),
+ way = iD.Way({nodes: [node.id]}),
+ graph = iD.Graph([node, way]);
+ expect(way.intersects([[-5, -5], [5, 5]], graph)).to.equal(true);
+ });
+
+ it("returns false for way with no nodes within the given extent", function () {
+ var node = iD.Node({loc: [6, 6]}),
+ way = iD.Way({nodes: [node.id]}),
+ graph = iD.Graph([node, way]);
+ expect(way.intersects([[-5, -5], [5, 5]], graph)).to.equal(false);
+ });
+ });
+
describe("#hasInterestingTags", function () {
it("returns false if the entity has no tags", function () {
expect(iD.Entity().hasInterestingTags()).to.equal(false);
diff --git a/test/spec/graph/history.js b/test/spec/graph/history.js
index 15fe10964..554b22a82 100644
--- a/test/spec/graph/history.js
+++ b/test/spec/graph/history.js
@@ -126,6 +126,34 @@ describe("iD.History", function () {
});
});
+ describe("#hasChanges", function() {
+ it("is true when any of change's values are nonempty", function() {
+ var node = iD.Node();
+ history.perform(function (graph) { return graph.replace(node); });
+ expect(history.hasChanges()).to.eql(true);
+ });
+
+ it("is false when all of change's values are empty", function() {
+ expect(history.hasChanges()).to.eql(false);
+ });
+ });
+
+ describe("#numChanges", function() {
+ it("is 0 when there are no changes", function() {
+ expect(history.numChanges()).to.eql(0);
+ });
+
+ it("is the sum of all types of changes", function() {
+ var node1 = iD.Node({id: "n1"}),
+ node2 = iD.Node();
+ history.merge(iD.Graph([node1]));
+ history.perform(function (graph) { return graph.remove(node1); });
+ expect(history.numChanges()).to.eql(1);
+ history.perform(function (graph) { return graph.replace(node2); });
+ expect(history.numChanges()).to.eql(2);
+ });
+ });
+
describe("#reset", function () {
it("clears the version stack", function () {
history.perform(action, "annotation");
diff --git a/test/spec/graph/relation.js b/test/spec/graph/relation.js
index 8880fc98c..f8b49a213 100644
--- a/test/spec/graph/relation.js
+++ b/test/spec/graph/relation.js
@@ -55,6 +55,55 @@ describe('iD.Relation', function () {
});
});
+ describe("#geometry", function () {
+ it("returns 'relation'", function () {
+ expect(iD.Relation().geometry()).to.equal('relation');
+ });
+ });
+
+ describe("#memberByRole", function () {
+ it("returns the first member with the given role", function () {
+ var r = iD.Relation({members: [
+ {id: 'a', role: 'inner'},
+ {id: 'b', role: 'outer'},
+ {id: 'c', role: 'outer'}]});
+ expect(r.memberByRole('outer')).to.eql({id: 'b', role: 'outer', index: 1});
+ });
+
+ it("returns undefined if no members have the given role", function () {
+ expect(iD.Relation().memberByRole('outer')).to.be.undefined;
+ });
+ });
+
+ describe("#memberById", function () {
+ it("returns the first member with the given id", function () {
+ var r = iD.Relation({members: [
+ {id: 'a', role: 'outer'},
+ {id: 'b', role: 'outer'},
+ {id: 'b', role: 'inner'}]});
+ expect(r.memberById('b')).to.eql({id: 'b', role: 'outer', index: 1});
+ });
+
+ it("returns undefined if no members have the given role", function () {
+ expect(iD.Relation().memberById('b')).to.be.undefined;
+ });
+ });
+
+ describe("#isRestriction", function () {
+ it("returns true for 'restriction' type", function () {
+ expect(iD.Relation({tags: {type: 'restriction'}}).isRestriction()).to.be.true;
+ });
+
+ it("returns true for 'restriction:type' types", function () {
+ expect(iD.Relation({tags: {type: 'restriction:bus'}}).isRestriction()).to.be.true;
+ });
+
+ it("returns false otherwise", function () {
+ expect(iD.Relation().isRestriction()).to.be.false;
+ expect(iD.Relation({tags: {type: 'multipolygon'}}).isRestriction()).to.be.false;
+ });
+ });
+
describe("#multipolygon", function () {
specify("single polygon consisting of a single way", function () {
var a = iD.Node(),
diff --git a/test/spec/graph/way.js b/test/spec/graph/way.js
index 19a4514db..37df6b648 100644
--- a/test/spec/graph/way.js
+++ b/test/spec/graph/way.js
@@ -35,6 +35,28 @@ describe('iD.Way', function() {
expect(iD.Way({tags: {foo: 'bar'}}).tags).to.eql({foo: 'bar'});
});
+ describe("#first", function () {
+ it("returns the first node", function () {
+ expect(iD.Way({nodes: ['a', 'b', 'c']}).first()).to.equal('a');
+ });
+ });
+
+ describe("#last", function () {
+ it("returns the last node", function () {
+ expect(iD.Way({nodes: ['a', 'b', 'c']}).last()).to.equal('c');
+ });
+ });
+
+ describe("#contains", function () {
+ it("returns true if the way contains the given node", function () {
+ expect(iD.Way({nodes: ['a', 'b', 'c']}).contains('b')).to.be.true;
+ });
+
+ it("returns false if the way does not contain the given node", function () {
+ expect(iD.Way({nodes: ['a', 'b', 'c']}).contains('d')).to.be.false;
+ });
+ });
+
describe("#extent", function () {
it("returns the minimal extent containing all member nodes", function () {
var node1 = iD.Node({loc: [0, 0]}),
@@ -45,22 +67,6 @@ describe('iD.Way', function() {
});
});
- describe("#intersects", function () {
- it("returns true for a way with a node within the given extent", function () {
- var node = iD.Node({loc: [0, 0]}),
- way = iD.Way({nodes: [node.id]}),
- graph = iD.Graph([node, way]);
- expect(way.intersects([[-5, -5], [5, 5]], graph)).to.equal(true);
- });
-
- it("returns false for way with no nodes within the given extent", function () {
- var node = iD.Node({loc: [6, 6]}),
- way = iD.Way({nodes: [node.id]}),
- graph = iD.Graph([node, way]);
- expect(way.intersects([[-5, -5], [5, 5]], graph)).to.equal(false);
- });
- });
-
describe('#isClosed', function() {
it('returns false when the way has no nodes', function() {
expect(iD.Way().isClosed()).to.equal(false);
diff --git a/test/spec/ui/flash.js b/test/spec/ui/flash.js
index 0426d1734..2b43ef83e 100644
--- a/test/spec/ui/flash.js
+++ b/test/spec/ui/flash.js
@@ -1,13 +1,17 @@
describe("iD.ui.flash", function () {
- it('can be instantiated', function () {
- var flash = iD.ui.flash();
- expect(flash).to.be.ok;
+ var clock;
+
+ beforeEach(function () {
+ clock = sinon.useFakeTimers();
});
- it('leaves after 1000 ms', function (done) {
+
+ afterEach(function () {
+ clock.restore();
+ });
+
+ it('leaves after 1000 ms', function () {
var flash = iD.ui.flash();
- window.setTimeout(function() {
- expect(flash.node().parentNode).to.be.null;
- done();
- }, 1200);
+ clock.tick(1010);
+ expect(flash.node().parentNode).to.be.null;
});
});
diff --git a/test/spec/ui/inspector.js b/test/spec/ui/inspector.js
index baa830e76..1a4df1899 100644
--- a/test/spec/ui/inspector.js
+++ b/test/spec/ui/inspector.js
@@ -57,11 +57,11 @@ describe("iD.ui.inspector", function () {
expect(inspector.tags()).to.eql({});
});
- it("emits a close event when the close button is clicked", function () {
+ it("emits a close event when the apply button is clicked", function () {
var spy = sinon.spy();
inspector.on('close', spy);
- element.select('.close').trigger('click');
+ element.select('.apply').trigger('click');
expect(spy).to.have.been.calledWith(entity);
});