diff --git a/media/css/ecosystem/documentation.less b/media/css/ecosystem/documentation.less new file mode 100644 index 00000000000..a56a3d89cb7 --- /dev/null +++ b/media/css/ecosystem/documentation.less @@ -0,0 +1,106 @@ +@import '../mkt/lib'; + +.design-wrapper { + margin: 0 auto; + position: relative; + width: 960px; +} + +.secondary-landing nav.design { + float: left; + margin-bottom: 40px; + padding-right: 20px; + width: 205px; + ol, ul { + padding-left: 10px; + } + ol { + > li { + > a { + font-size: 13px; + font-weight: normal; + } + } + } + ul { + > li { + color: @dark-gray; + font-size: 15px; + > a, > span { + background-color: #f4f4f4; + color: @dark-gray; + display: block; + font-size: 15px; + font-weight: normal; + margin-bottom: 2px; + padding: 5px; + width: 100%; + } + } + } +} + +.secondary-landing article { + float: left; + margin: 25px 0 20px 20px; + width: 660px; + + h1 { + margin-top: 0; + } + + h2 { + font-size: 26px; + margin: 30px 0 10px; + } + + &.marketing-block { + padding-top: 0px; + } +} + +.sample-run-js { + clear: both; + float: left; + margin: 10px 0 30px; + outline: none; + width: 100%; + + p { + font-size: 14px; + line-height: 16px; + padding: 10px; + } +} + +.tips { + clear: both; + display: block; + float: left; + margin-left: 20px; + width: 95%; + + > ul { + clear: both; + display: block; + float: left; + padding: 0 0 20px; + width: 95%; + } + + li { + clear: both; + display: block; + float: left; + line-height: 23px; + width: 100%; + } +} + +#page > section.document-breadcrumb { + padding-top: 15px; + width: 960px; + a, span { + font-size: 25px; + } +} diff --git a/media/css/ecosystem/footer.less b/media/css/ecosystem/footer.less index b5928118325..42329d573f0 100644 --- a/media/css/ecosystem/footer.less +++ b/media/css/ecosystem/footer.less @@ -1,3 +1,4 @@ +@import '../mkt/lib'; #site-footer { border-top: 1px solid #ddd; @@ -22,12 +23,20 @@ margin-top: 2px; } margin-top: 0; + + &.user-actions { + float: left; + padding: 0; + text-align: left; + } } li { list-style: none; } #footzilla { background: url(../../img/hub/footzilla.png) no-repeat; + color: #424f5a; + display: block; float: left; height: 50px; margin-top: 5px; @@ -36,3 +45,18 @@ width: 100px; } } + +@media (max-width: @4col) { + #site-footer { + color: #eee; + a { + color: #83cef3; + } + ul, p { + border: none; + } + #footzilla, .legal { + display: none; + } + } +} diff --git a/media/css/ecosystem/landing.less b/media/css/ecosystem/landing.less index 6a9a3b6b6d6..826d8d1ce80 100755 --- a/media/css/ecosystem/landing.less +++ b/media/css/ecosystem/landing.less @@ -15,8 +15,9 @@ body { #site-header { .logo a { - background-image: url('../../img/ecosystem/developers_logo.png'); + background-image: url(../../img/ecosystem/developers_logo.png); height: 54px; + margin: 0px; width: 375px; } nav { @@ -24,9 +25,9 @@ body { text-align: right; } nav a { - margin-left: 25px; padding-top: 25px; color: #6DC7FF; + margin-left: 25px; text-transform: uppercase; font-size: 13pt; text-shadow: 0 1px 1px #444; @@ -38,7 +39,7 @@ body { } } a.external { - background-image: url('../../img/mkt/arrows/external_menu.gif'); + background-image: url(../../img/mkt/arrows/external_menu.gif); background-position: right 33px; background-repeat: no-repeat; padding-right: 12px; @@ -63,6 +64,11 @@ body { #landing-page { max-width: 984px; width: 90%; + + nav { + float: right; + max-width: 450px; + } } #top-marketing { @@ -76,6 +82,10 @@ body { max-height: 250px; max-width: 70%; } + p { + margin: 0 auto; + width: 70%; + } } .call-to-action { @@ -101,55 +111,61 @@ body { } } +.secondary-landing { + h2 { + margin-bottom: 20px; + } +} + #rotator { float: right; } #landing-page { margin: 0 auto 25px; + width: 984px; img { max-width: 100%; } } -#demo-block { - padding-bottom: 0; -} - -#demo-list { - max-width:485px; - float:left; +.marketing-horz { margin: 0; padding: 0; + width: 100%; + .link-panel { + color: @medium-gray; + display: block; + + &:hover { + text-decoration: none; + } + } li { + .border-box; list-style: none; - display: inline-block; - margin-bottom: 20px; - } - .placeholder { - height: 120px; - width: 200px; - display: inline; - margin-right: 20px; + text-align: center; + float: left; + max-width: 50%; + padding: 0 10px; + width: 50%; + + a { + color: @link; + } } - span { - display: block; + li div { + margin: 0 auto; } - a { - color: @medium-gray; - img { - opacity: .9; - } - &:hover { - color: @dark-gray; - img { - opacity: 1; - } - } + + &.support-content li { + text-align: left; + max-width: 100%; + width: 100%; } } -#marketing-horz { +.marketing-horz.four-cols { margin: 0; padding: 0; width: 100%; @@ -158,15 +174,51 @@ body { list-style: none; text-align: center; float: left; - max-width: 33.3%; - padding: 0 10px; - width: 33.33%; + max-width: 25%; + padding: 10px; + width: 25%; } li div { margin: 0 auto; } } +.marketing-block.half { + float: left; + margin-bottom: 25px; + min-height: 280px; + width: 43.5%; + #marketing-horz { + li { + margin-bottom: 5px; + max-width: 100%; + padding: 0; + text-align: left; + width: 100%; + } + } + + &.primary { + margin-right: 20px; + } + + img.logo { + width: 100%; + } +} + +.marketing-block.single { + width: 100%; + + li { + max-width: 100%; + width: 100%; + h2 { + margin-top: 20px; + } + } +} + #page { &:before { content: "."; @@ -174,12 +226,16 @@ body { height: 0; overflow: hidden; } + + h1 { + margin-top: 20px; + } } .marketing-block { .box-shadow(0 1px 5px -3px @black); overflow: hidden; - background-color: white; + background-color: #fff; padding: 25px; margin: 25px auto 0; border: 1px solid #bbb; @@ -188,6 +244,26 @@ body { } } +.partners { + .marketing-block { + min-height: 125px; + &.reach { + background: url(../../img/ecosystem/reach_icon.png) no-repeat #fff; + } + + &.choice { + background: url(../../img/ecosystem/open_icon.png) no-repeat #fff; + } + + &.open { + background: url(../../img/ecosystem/html_icon.png) no-repeat #fff; + } + h2, ul { + padding-left: 300px; + } + } +} + .img-right { .placeholder { float: right; @@ -201,75 +277,9 @@ body { padding: 0; } -#tutorial { - margin: 25px auto 25px auto; - max-width: 984px; - width: 90%; - background-color: #EFF1F2; - padding: 0; - - h3 { - font-size: 23px; - margin-top: 8px; - } - a { - color: #667990; - } - pre { - border: dashed 2px #ddd; - overflow: auto; - padding: 10px; - white-space: pre; - } - - nav ul { - padding: 0; - margin: 0; - } - nav li { - margin: 2px 0 2px 0; - } - nav img { - box-shadow: 0 0 5px #aaa; - border: solid 1px #E3E5E6; - } - - #sidebar { - width: 225px; - float: left; - margin-left: -100%; - padding: 25px 0 25px 25px; - font-size: 15px; - color: #667990; - a { - display: block; - margin-left: 15px; - text-indent: -15px; - } - a.external { - background: url(../../img/mkt/arrows/external_sidebar.gif) 100% 50% no-repeat; - padding-right: 12px; - } - } - #content { - float: left; - width: 100%; - } - #mdn-content { - margin-left: 275px; - background-color: #fff; - padding: 25px; - border-left: solid 1px #E3E5E6; - } - #mdn-toc { - margin: 0; - padding: 0 0 0 20px; - li span { - display: none; - } - ol { - display: none; - } +#site-footer { + ul, p.legal { + border: 0; } } @@ -296,6 +306,11 @@ body { } } + #site-header .wrapper nav { + float: left; + width: auto; + } + #page { margin-top: 0; } @@ -331,10 +346,12 @@ body { } } } - #site-header nav a { - text-transform: none; - + a { - margin-left: 10px; + #site-header nav { + a { + text-transform: none; + + a { + margin-left: 10px; + } } } #landing-page #marketing-horz { @@ -360,6 +377,7 @@ body { @media (max-width: 800px) { #site-header { + height: 130px; &:after { height: 8px; top: -28px; @@ -374,15 +392,4 @@ body { z-index: 1; } } - #tutorial { - nav img { - display: none; - } - #content { - width: 100%; - } - #mdn-content, #sidebar { - margin-left: 0; - } - } } diff --git a/media/css/ecosystem/xtags/alert-popup.css b/media/css/ecosystem/xtags/alert-popup.css new file mode 100644 index 00000000000..8935824703d --- /dev/null +++ b/media/css/ecosystem/xtags/alert-popup.css @@ -0,0 +1,93 @@ +x-alert { + position: fixed; + padding: 15px 25px; + text-align: center; + background: #222; + color: #eee; + + /* so that the alert popup doesn't flash for a split second on load */ + opacity: 0; +} + +x-alert { + /* flex box container to center inner elements */ + display: -webkit-box; + display: -moz-box; + display: -ms-box; + display: -o-box; + display: box; + + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + + -webkit-box-align: center; + -moz-box-align: center; + -ms-box-align: center; + -o-box-align: center; + box-align: center; + + -webkit-align-items: center; + -moz-align-items: center; + -ms-align-items: center; + -o-align-items: center; + align-items: center; + + -webkit-box-pack: center; + -moz-box-pack: center; + -ms-box-pack: center; + -o-box-pack: center; + box-pack: center; + + -webkit-justify-content: center; + -moz-justify-content: center; + -ms-justify-content: center; + -o-justify-content: center; + justify-content: center; + + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -ms-box-orient: vertical; + -o-box-orient: vertical; + box-orient: vertical; + + -webkit-flex-direction: column; + -moz-flex-direction: column; + -ms-flex-direction: column; + -o-flex-direction: column; + flex-direction: column; +} + +x-alert[data-location='bottom'] { + top: auto; + bottom: 10px; +} + +x-alert[data-location='top'] { + top: 10px; + bottom: auto; +} + +x-alert h1, x-alert h2, x-alert h3, x-alert h4, x-alert h5, x-alert h6 { + margin-top: 0; + padding-bottom: 5px; + border-bottom: 1px solid #bbb; +} + +.x-alert-primary, .x-alert-secondary { + display: inline-block; + padding: 5px 15px; + background: #ccc; + color: #222; + text-decoration: none; + margin-top: 20px; + margin-right: 10px; + + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + -ms-border-radius: 5px; + -o-border-radius: 5px; + border-radius: 5px; +} diff --git a/media/css/ecosystem/xtags/dialog-toast.css b/media/css/ecosystem/xtags/dialog-toast.css new file mode 100644 index 00000000000..b07998a3d38 --- /dev/null +++ b/media/css/ecosystem/xtags/dialog-toast.css @@ -0,0 +1,26 @@ +x-toast { + display: none; + position: fixed; + bottom: 10px; + padding: 15px 25px; + text-align: center; + background: #222; + color: #eee; +} + +x-toast[data-location="top"] { + top: 10px; + bottom: auto; +} + +x-toast[data-show] { + display: block; +} + +x-toast .close { + position: absolute; + top: 0; + right: 5px; + color: #eee; + text-decoration: none; +} diff --git a/media/css/ecosystem/xtags/listview.css b/media/css/ecosystem/xtags/listview.css new file mode 100644 index 00000000000..78d71c5a3b3 --- /dev/null +++ b/media/css/ecosystem/xtags/listview.css @@ -0,0 +1,32 @@ +x-listview { + display: block; + overflow: auto; + padding: 4px; +} +x-listview > x-section{ + margin-top: 8px; + display: block; + +} +x-listview > x-section:first-child{ + margin: 0; + padding: 0; +} +x-listview > x-section > x-header { + font-size: 1.5em; + border-bottom: solid 1px #000; + margin-bottom: 5px; + padding-left:10px; + line-height: 1em; + display: block; +} +x-listview x-listitem { + font-size: 1em; + margin: 0; + padding: 1px 0 0 10px; + border-bottom: solid 1px #ddd; + display: block; +} +x-listitem[selected]{ + background-color: #eef; +} diff --git a/media/css/ecosystem/xtags/slidebox.css b/media/css/ecosystem/xtags/slidebox.css new file mode 100644 index 00000000000..f4aa7eb500a --- /dev/null +++ b/media/css/ecosystem/xtags/slidebox.css @@ -0,0 +1,28 @@ +x-slidebox { + display: block; + overflow: hidden; +} + +x-slides { + display: block; + position: relative; + height: 100%; + width: 100%; + overflow: hidden; + transition: transform 0.5s ease 0s; + -o-transition: -o-transform 0.5s ease 0s; + -ms-transition: -ms-transform 0.5s ease 0s; + -moz-transition: -moz-transform 0.5s ease 0s; + -webkit-transition: -webkit-transform 0.5s ease 0s; +} + +x-slides > x-slide { + display: block; + float: left; + height: 100%; + width: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + -o-box-sizing: border-box; +} diff --git a/media/css/ecosystem/xtags/slider.css b/media/css/ecosystem/xtags/slider.css new file mode 100644 index 00000000000..62340e29065 --- /dev/null +++ b/media/css/ecosystem/xtags/slider.css @@ -0,0 +1,58 @@ +x-slider { + display: block; +} +x-slider label { + +} + +x-slider div.x-slider-container { + display: box; + display: -o-box; + display: -ms-box; + display: -moz-box; + display: -webkit-box; + width: 100%; + +} +x-slider div.x-slider-min { + box-flex: 0; + -o-box-flex: 0; + -ms-box-flex: 0; + -moz-box-flex: 0; + -webkit-box-flex: 0; +} +x-slider div.x-slider-max { + box-flex: 0; + -o-box-flex: 0; + -ms-box-flex: 0; + -moz-box-flex: 0; + -webkit-box-flex: 0; +} +x-slider div.x-slider-range { + box-flex: 1; + -o-box-flex: 1; + -ms-box-flex: 1; + -moz-box-flex: 1; + -webkit-box-flex: 1; + margin: 0 5px 0 5px; + border: solid 1px red; + +} +x-slider div.x-slider-knob { + width: 10px; + border: solid 1px #000; + cursor: pointer; + transform: translate(-50%); + -webkit-transform: translate(-50%); +} +body.x-tag-slider-drag{ + user-select: none; + -o-user-select: none; + -ms-user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + cursor: ew-resize; +} +body.x-tag-slider-drag div.x-slider-knob { + cursor: ew-resize; +} diff --git a/media/css/ecosystem/xtags/tabbox.css b/media/css/ecosystem/xtags/tabbox.css new file mode 100644 index 00000000000..067ab213368 --- /dev/null +++ b/media/css/ecosystem/xtags/tabbox.css @@ -0,0 +1,85 @@ + +x-tabbox, x-tabs, x-tab { + display: inline-block; + display: box; + display: -o-box; + display: -ms-box; + display: -moz-box; + display: -webkit-box; +} + +x-tabbox, x-tabpanels, x-tabpanel { + box-orient: vertical; + -o-box-orient: vertical; + -ms-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-box-orient: vertical; +} + +x-tabs, x-tab, x-tabpanels { + box-flex: 0; + -o-box-flex: 0; + -ms-box-flex: 0; + -moz-box-flex: 0; + -webkit-box-flex: 0; +} + +x-tab { + cursor: default; +} + +x-tab[selected="true"] { + text-decoration: underline; +} + +x-tabpanels > x-tabpanel { + display: none; +} + +x-tabpanels, x-tabpanels > *[selected="true"] { + display: block; +} + +x-tabbox[tab-orient="left"], x-tabbox[tab-orient="right"] { + box-orient: horizontal; + -o-box-orient: horizontal; + -ms-box-orient: horizontal; + -moz-box-orient: horizontal; + -webkit-box-orient: horizontal; +} + +x-tabbox[tab-orient="bottom"] { + box-direction: reverse; + -o-box-direction: reverse; + -ms-box-direction: reverse; + -moz-box-direction: reverse; + -webkit-box-direction: reverse; +} + +x-tabbox[tab-orient="left"] x-tabs, +x-tabbox[tab-orient="right"] x-tabs, +x-tabbox[tab-orient="left"] x-tabpanels, +x-tabbox[tab-orient="right"] x-tabpanels { + box-flex: 1; + -o-box-flex: 1; + -ms-box-flex: 1; + -moz-box-flex: 1; + -webkit-box-flex: 1; + box-orient: vertical; + -o-box-orient: vertical; + -ms-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-box-orient: vertical; +} + +x-tabbox[tab-orient="right"] { + box-direction: reverse; + -o-box-direction: reverse; + -ms-box-direction: reverse; + -moz-box-direction: reverse; + -webkit-box-direction: reverse; +} + +x-tabbox[tab-orient="right"] x-tabs, x-tabbox[tab-orient="bottom"] x-tabs{ + -webkit-box-direction: normal; +} diff --git a/media/img/ecosystem/evernote.png b/media/img/ecosystem/evernote.png deleted file mode 100644 index 0e23e9f990c..00000000000 Binary files a/media/img/ecosystem/evernote.png and /dev/null differ diff --git a/media/img/ecosystem/stackoverflow_logo.jpg b/media/img/ecosystem/stackoverflow_logo.jpg new file mode 100644 index 00000000000..8eeb09cb205 Binary files /dev/null and b/media/img/ecosystem/stackoverflow_logo.jpg differ diff --git a/media/js/mkt/xtags/alert-popup.js b/media/js/mkt/xtags/alert-popup.js new file mode 100644 index 00000000000..036640042b6 --- /dev/null +++ b/media/js/mkt/xtags/alert-popup.js @@ -0,0 +1,139 @@ +(function(window, document, undefined) { + var primaryTextAttr = 'data-primary-text'; + var secondaryTextAttr = 'data-secondary-text'; + var locationAttr = 'data-location'; + var fadeDurationAttr = 'data-fade-duration'; + + xtag.register('x-alert', { + onCreate: function() { + this.primaryText = this.getAttribute(primaryTextAttr); + this.secondaryText = this.getAttribute(secondaryTextAttr); + this.location = this.getAttribute(locationAttr); + this.fadeDuration = this.getAttribute(fadeDurationAttr); + }, + + onInsert: function() { + var self = this; + + var actionsSelector = '.x-alert-actions'; + if (xtag.query(self, actionsSelector).length === 0) { + self.innerHTML += '
'; + } + + var actions = xtag.query(self, actionsSelector)[0]; + ['secondary', 'primary'].forEach(function(type) { + var selector = '.x-alert-' + type; + + // insert a primary and secondary button if not already present + if (xtag.query(self, selector).length === 0 && self[type + 'Text']) { + var button = document.createElement('a'); + button.href= '#' + type; + button.className = selector.substring(1); + button.innerHTML = self[type + 'Text']; + + actions.appendChild(button); + button.addEventListener('click', function(event) { + event.preventDefault(); + self.xtag.dismiss(type); + }); + } + }); + + // center the alert relative to the window + self.style.left = ( window.innerWidth / 2 - self.offsetWidth / 2 ) + 'px'; + if (self.location === 'center') { + self.style.top = ( window.innerHeight / 2 - self.offsetHeight / 2 ) + 'px'; + } + + self.style.display = 'none'; + self.xtag.display(); + }, + + setters: { + primaryText: function(primaryText) { + // defaults to OK + primaryText = primaryText || 'OK'; + this.setAttribute(primaryTextAttr, primaryText); + }, + + secondaryText: function(secondaryText) { + if (secondaryText) { + this.setAttribute(secondaryTextAttr, secondaryText); + } + }, + + fadeDuration: function(fadeDuration) { + // default fade duration is 150 ms + fadeDuration = parseInt(fadeDuration, 10); + + // since fadeDuration can be 0, check for NaN explicitly + if (isNaN(fadeDuration)) { + fadeDuration = 150; + } + + this.style[xtag.prefix.js + 'Transition'] = 'opacity ' + fadeDuration + 'ms'; + this.setAttribute(fadeDurationAttr, fadeDuration); + }, + + location: function(location) { + // default location is center + if (location !== 'top' && location !== 'bottom') { + location = 'center'; + } + + this.setAttribute(locationAttr, location); + } + }, + + getters: { + primaryText: function() { + return this.getAttribute(primaryTextAttr); + }, + + secondaryText: function() { + return this.getAttribute(secondaryTextAttr); + }, + + fadeDuration: function() { + return parseInt(this.getAttribute(fadeDurationAttr), 10); + }, + + location: function() { + return this.getAttribute(locationAttr); + } + }, + + methods: { + /** + * Displays this alert, triggering a show event. + */ + display: function() { + var self = this; + + // only activate if not already displayed + if (self.style.display === 'none') { + self.style.opacity = 1; + self.style.removeProperty('display'); + xtag.fireEvent(self, 'show'); + } + }, + + /** + * Dismisses this alert, triggering a hide event. + */ + dismiss: function(type) { + var self = this; + + // only deactivate if not already hidden + if (self.style.display !== 'none') { + self.style.opacity = 0; + + setTimeout(function() { + self.style.display = 'none'; + xtag.fireEvent(self, 'hide', { dismissType: type }); + }, self.fadeDuration); + } + } + } + }); +})(this, this.document); diff --git a/media/js/mkt/xtags/dialog-toast.js b/media/js/mkt/xtags/dialog-toast.js new file mode 100644 index 00000000000..fce1f626cf5 --- /dev/null +++ b/media/js/mkt/xtags/dialog-toast.js @@ -0,0 +1,110 @@ +(function(window, document, undefined) { + var durationAttr = 'data-duration'; + var locationAttr = 'data-location'; + var excludeCloseAttr = 'data-exclude-close'; + + xtag.register('x-toast', { + onCreate: function() { + this.duration = this.getAttribute(durationAttr); + this.location = this.getAttribute(locationAttr); + this.excludeClose = this.getAttribute(excludeCloseAttr); + }, + + onInsert: function() { + // insert a close button if not already present + var closeSelector = '.close'; + if (!this.excludeClose && xtag.query(this, closeSelector).length === 0) { + this.innerHTML += '×'; + + var close = xtag.query(this, closeSelector)[0]; + var self = this; + close.addEventListener('click', function(event) { + event.preventDefault(); + self.xtag.hide(); + }); + } + + this.xtag.show(); + }, + + setters: { + duration: function(duration) { + // default duration is 3 seconds + duration = parseInt(duration, 10) || 3000; + this.setAttribute(durationAttr, duration); + }, + + location: function(location) { + // default location is bottom + if (location !== 'top') { + location = 'bottom'; + } + + this.setAttribute(locationAttr, location); + }, + + excludeClose: function(excludeClose) { + if (excludeClose) { + this.setAttribute(excludeCloseAttr, 'true'); + } else { + this.removeAttribute(excludeCloseAttr); + } + } + }, + + getters: { + duration: function() { + return parseInt(this.getAttribute(durationAttr), 10); + }, + + location: function() { + return this.getAttribute(locationAttr); + }, + + excludeClose: function() { + return this.getAttribute(excludeCloseAttr); + } + }, + + methods: { + /** + * Makes this toast appear for the interval specified by the data-duration + * attribute or duration property. + */ + show: function() { + var self = this; + + // only show if not already displayed + if (!self.getAttribute('data-show')) { + self.setAttribute('data-show', 'true'); + // center the toast relative to the window + this.style.left = ( window.innerWidth / 2 - this.offsetWidth / 2 ) + 'px'; + + xtag.fireEvent(self, 'show'); + self.durationTimeout = setTimeout(function() { + self.durationTimeout = null; + self.xtag.hide(); + }, self.duration); + } + }, + + /** + * Makes this toast disappear if it is not hidden already. + */ + hide: function() { + var self = this; + + if (self.durationTimeout) { + clearTimeout(self.durationTimeout); + self.durationTimeout = null; + } + + // only hide if not already hidden + if (self.getAttribute('data-show')) { + self.removeAttribute('data-show'); + xtag.fireEvent(self, 'hide'); + } + } + } + }); +})(this, this.document); diff --git a/media/js/mkt/xtags/listview.js b/media/js/mkt/xtags/listview.js new file mode 100644 index 00000000000..5a4de5af3ce --- /dev/null +++ b/media/js/mkt/xtags/listview.js @@ -0,0 +1,56 @@ +(function(){ + + xtag.register('x-listview', { + onCreate: function(){ + this.yPos = 0; + this.mouseDown = false; + }, + events:{ + 'mousemove': function(e){ + if (this.mouseDown) { + this.scrollTop = (this.yPos - e.clientY); + } + }, + 'mousedown': function(e) { + this.yPos = this.scrollTop + e.clientY; + this.mouseDown = true; + }, + 'mouseup': function(e){ + this.mouseDown = false; + this.yPos = 0; + }, + }, + methods:{ + getSelected: function(){ + return xtag.query(this, 'x-listitem[selected]'); + } + } + }); + + + xtag.register('x-listitem', { + onInsert: function(){ + xtag.fireEvent(this,"nodeinserted"); + this.setAttribute('tabindex',0); + }, + events:{ + 'mousedown': function(e) { + var self = this; + setTimeout(function(){ + var p = self.parentNode; + while(p && p.nodeName != 'X-LISTVIEW' && p.nodeName != 'BODY'){ + p = p.parentNode; + } + if (p && p.nodeName == 'X-LISTVIEW' && !p.mouseDown){ + var none = self.attributes['selected'] ? + self.removeAttribute('selected') : + self.setAttribute('selected', null); + xtag.fireEvent(self, "itemselected"); + } + + }, 150); + } + } + }); + +})(); diff --git a/media/js/mkt/xtags/slidebox.js b/media/js/mkt/xtags/slidebox.js new file mode 100644 index 00000000000..a965032082b --- /dev/null +++ b/media/js/mkt/xtags/slidebox.js @@ -0,0 +1,76 @@ +(function(){ + + var transform = xtag.prefix.js + 'Transform', + getState = function(el){ + var selected = xtag.query(el, 'x-slides > x-slide[selected="true"]')[0] || 0; + return [selected ? xtag.query(el, 'x-slides > x-slide').indexOf(selected) : selected, el.firstElementChild.children.length - 1]; + }, + slide = function(el, index){ + var slides = xtag.toArray(el.firstElementChild.children); + slides.forEach(function(slide){ slide.removeAttribute('selected'); }); + slides[index || 0].setAttribute('selected', true); + el.firstElementChild.style[transform] = 'translate'+ (el.getAttribute('data-orientation') || 'x') + '(' + (index || 0) * (-100 / slides.length) + '%)'; + }, + init = function(toSelected){ + var slides = this.firstElementChild; + if (!slides || !slides.children.length || slides.tagName.toLowerCase() != 'x-slides') return; + + var children = xtag.toArray(slides.children), + size = 100 / (children.length || 1), + orient = this.getAttribute('data-orientation') || 'x', + style = orient == 'x' ? ['width', 'height'] : ['height', 'width']; + + xtag.skipTransition(slides, function(){ + slides.style[style[1]] = '100%'; + slides.style[style[0]] = children.length * 100 + '%'; + slides.style[transform] = 'translate' + orient + '(0%)'; + children.forEach(function(slide){ + slide.style[style[0]] = size + '%'; + slide.style[style[1]] = '100%'; + }); + }); + + if (toSelected) { + var selected = slides.querySelector('[selected="true"]'); + if (selected) slide(this, children.indexOf(selected) || 0); + } + }; + + xtag.register('x-slidebox', { + onInsert: init, + events:{ + 'transitionend': function(e){ + if (e.target == this) xtag.fireEvent(this, 'slideend'); + } + }, + setters: { + 'data-orientation': function(value){ + this.setAttribute('data-orientation', value.toLowerCase()); + init.call(this, true); + }, + }, + methods: { + slideTo: function(index){ + slide(this, index); + }, + slideNext: function(){ + var shift = getState(this); + shift[0]++; + slide(this, shift[0] > shift[1] ? 0 : shift[0]); + }, + slidePrevious: function(){ + var shift = getState(this); + shift[0]--; + slide(this, shift[0] < 0 ? shift[1] : shift[0]); + } + } + }); + + xtag.register('x-slide', { + onInsert: function(){ + var ancestor = this.parentNode.parentNode; + if (ancestor.tagName.toLowerCase() == 'x-slidebox') init.call(ancestor, true); + } + }); + +})(); diff --git a/media/js/mkt/xtags/slider.js b/media/js/mkt/xtags/slider.js new file mode 100644 index 00000000000..ac00de6d447 --- /dev/null +++ b/media/js/mkt/xtags/slider.js @@ -0,0 +1,155 @@ +(function(window, document, undefined){ + + xtag.addEvent(document, 'mouseup:touch', function(e){ + xtag.removeClass(document.body,'x-tag-slider-drag'); + if (selected){ + xtag.removeClass(selected.xtag.knob, 'x-tag-slider-knob-moving'); + xtag.removeEvent(document, 'mousemove:touch', selected.xtag.mouseMoveFn); + } + selected = null; + }); + + var selected = null; + var mouseMove = function(e){ + if (selected) { + var range = selected.xtag.knob.parentNode; + var position = Math.round( + (e.clientX - range.offsetLeft) / + (range.offsetWidth) * 1000)/10; + position = position > 100 ? 100 : position < 0 ? 0 : position; + + var translatedValue = (selected.dataset.max - selected.dataset.min) * (position / 100); + for (var step = 0; step < selected.xtag.stepTable.length-1; step++){ + var stepValue = selected.xtag.stepTable[step], + variance = selected.dataset.step/2, + high = Math.min(selected.dataset.max, stepValue+variance), + low = Math.max(selected.dataset.min, stepValue-variance); + if (translatedValue >= low && translatedValue <= high){ + break; + } + } + + var changed = Number(selected.xtag.input.value) != selected.xtag.stepTable[step]; + if (changed){ + selected.xtag.input.value = selected.xtag.stepTable[step]; + xtag.fireEvent(selected,'change', { value: selected.xtag.input.value }); + + if (selected.dataset.snap != undefined){ + selected.xtag.knob.style.marginLeft = ((step/(selected.xtag.stepTable.length-1))*100) + '%'; + } + } + if (selected.dataset.snap == undefined){ + selected.xtag.knob.style.marginLeft = position + '%'; + } + window.getSelection().removeAllRanges(); + } + } + + var initStepTable = function(min, max, step){ + for (var i = Number(this.dataset.min); i <= Number(this.dataset.max); i = i + Number(this.dataset.step)){ + this.xtag.stepTable.push(Number(i)); + } + } + + xtag.register('x-slider', { + onCreate: function(){ + var template = '
'+ + '
${minLabel}
' + + '
 
' + + '
${maxLabel}
' + + ''; + template = template.replace('${label}', this.dataset.label || 'Slider') + .replace('${minLabel}', this.dataset.minLabel || 0) + .replace('${maxLabel}', this.dataset.maxLabel || 10) + .replace('${name}', this.dataset.name || this.id || "") + .replace('${startValue}', this.dataset.startValue || ""); + this.innerHTML = template; + this.xtag.knob = xtag.query(this, '.x-slider-knob')[0]; + this.xtag.input = xtag.query(this, 'input')[0]; + this.xtag.stepTable = []; + this.dataset.step = this.dataset.step || 1; + this.dataset.min = this.dataset.min || 0; + this.dataset.max = this.dataset.max || 10; + initStepTable.call(this, + Number(this.dataset.min), + Number(this.dataset.max), + Number(this.dataset.step)); + if (this.dataset.startValue != undefined){ + this.xtag.knob.style.marginLeft = ((Number(this.dataset.startValue)/(Number(this.dataset.max)))*100) + '%'; + } + this.xtag.mouseMoveFn = null; + }, + onInsert: function(){ + }, + events:{ + 'mousedown:delegate(.x-slider-knob):touch': function(e, elem) { + selected = elem; + selected.xtag.mouseMoveFn = xtag.addEvent(document, 'mousemove:touch', mouseMove); + xtag.addClass(document.body,'x-tag-slider-drag'); + xtag.addClass(selected.xtag.knob, 'x-tag-slider-knob-moving'); + }, + 'click:delegate(.x-slider-range)': function(e, elem){ + if (e.target.className == 'x-slider-range'){ + selected = elem; + mouseMove(e); + selected = null; + } + }, + 'keydown:delegate(.x-slider-knob):keypass(37, 39)': function(e, elem){ + var currentValue = Number(elem.xtag.input.value); + for (var step = 0; step < elem.xtag.stepTable.length-1; step++){ + if (currentValue == elem.xtag.stepTable[step]){ + break; + } + } + step = e.keyCode == 37 ? step - 1 : step + 1; + if (step >= 0 && step <= elem.xtag.stepTable.length - 1){ + elem.xtag.knob.style.marginLeft = (step/(elem.xtag.stepTable.length-1)*100) + '%'; + elem.xtag.input.value = elem.xtag.stepTable[step]; + xtag.fireEvent(elem,'change', { value: elem.xtag.stepTable[step] }); + } + } + }, + setters: { + 'min:attribute(data-min)': function(value){ + initStepTable.call(this, + Number(value), + Number(this.dataset.max), + Number(this.dataset.step)); + }, + 'max:attribute(data-max)': function(value){ + initStepTable.call(this, + Number(this.dataset.min), + Number(value), + Number(this.dataset.step)); + }, + 'step:attribute(data-step)': function(value){ + initStepTable.call(this, + Number(this.dataset.min), + Number(this.dataset.max), + Number(value)); + }, + 'label:attribute(data-label)': function(value){ + var label = xtag.query(this, "label")[0]; + label.innerHTML = value; + }, + 'minLabel:attribute(data-min-label)': function(value){ + var label = xtag.query(this, ".x-slider-min")[0]; + label.innerHTML = value; + }, + 'maxLabel:attribute(data-max-label)': function(value){ + var label = xtag.query(this, ".x-slider-max")[0]; + label.innerHTML = value; + } + }, + getters: { + 'value' : function(){ + return Number(this.xtag.input.getAttribute('value')); + } + }, + methods: { + + } + }); + +})(this, this.document); diff --git a/media/js/mkt/xtags/tabbox.js b/media/js/mkt/xtags/tabbox.js new file mode 100644 index 00000000000..1329d60b153 --- /dev/null +++ b/media/js/mkt/xtags/tabbox.js @@ -0,0 +1,54 @@ +xtag.register('x-tabbox', { + events: { + 'tap:delegate(x-tab)': function(event){ + this.xtag.selectTab(); + }, + 'keydown:delegate(x-tab)': function(event){ + switch(event.keyCode) { + case 13: this.xtag.selectTab(); break; + case 37: this.parentNode.xtag.previousTab(); break; + case 39: this.parentNode.xtag.nextTab(); break; + } + } + } +}); + +xtag.register('x-tabs', { + methods: { + getSelectedIndex: function(){ + var tabs = xtag.query(this, 'x-tab'); + return tabs.indexOf(this.xtag.getSelectedTab()); + }, + getSelectedTab: function(){ + return xtag.query(this, 'x-tab[selected="true"]')[0]; + }, + nextTab: function(){ + var tab = this.xtag.getSelectedTab(); + if (tab) (tab.nextElementSibling || this.firstElementChild).xtag.selectTab(); + }, + previousTab: function(){ + var tab = this.xtag.getSelectedTab(); + if (tab) (tab.previousElementSibling || this.lastElementChild).xtag.selectTab(); + } + } +}); + + +xtag.register('x-tab', { + onCreate: function(){ + this.setAttribute('tabindex', 0); + }, + methods: { + selectTab: function(){ + this.focus(); + var tabs = xtag.query(this.parentNode, 'x-tab'), + index = tabs.indexOf(this); + tabs.forEach(function(el){ + el.setAttribute('selected', el == this ? true : ''); + }, this); + xtag.query(this.parentNode.parentNode, 'x-tabpanels > *').forEach(function(el, i, array){ + el.setAttribute('selected', el == array[index] ? true : ''); + }); + } + } +}); diff --git a/media/js/mkt/xtags/x-tag.js b/media/js/mkt/xtags/x-tag.js new file mode 100644 index 00000000000..46d7b1359a5 --- /dev/null +++ b/media/js/mkt/xtags/x-tag.js @@ -0,0 +1,462 @@ +(function(){ + + var head = document.getElementsByTagName('head')[0], + nodeInserted = function(element, query){ + if (query && element.childNodes.length) xtag.query(element, xtag.tagList).forEach(function(element){ nodeInserted(element) }); + xtag.extendElement(element, true); + if (element.parentNode) xtag.getOptions(element).onInsert.call(element); + }, + prefix = (function() { + var styles = window.getComputedStyle(document.documentElement, ''), + pre = (Array.prototype.slice.call(styles).join('').match(/moz|webkit|ms/)||(styles.OLink===''&&['o']))[0], + dom = ('WebKit|Moz|MS|O').match(new RegExp('(' + pre + ')', 'i'))[1]; + return { + dom: dom, + lowercase: pre, + css: '-' + pre + '-', + js: pre[0].toUpperCase() + pre.substr(1) + }; + })(), + mergeOne = function(source, key, current){ + switch (xtag.typeOf(current)){ + case 'object': + if (xtag.typeOf(source[key]) == 'object') xtag.merge(source[key], current); + else source[key] = xtag.clone(current); + break; + case 'array': source[key] = xtag.toArray(current); break; + default: source[key] = current; + } + return source; + }, + keypseudo = { + listener: function(pseudo, fn, args){ + if (!!~pseudo.value.match(/(\d+)/g).indexOf(String(event.keyCode)) == (pseudo.name == 'keypass')){ + args.splice(args.length, 0, this); + fn.apply(this, args); + } + } + }, + touchMap = { + mouseenter: 'touchenter', + mouseleave: 'touchleave', + mousedown: 'touchstart', + mousemove: 'touchmove', + mouseup: 'touchend', + click: 'touchend' + }; + + xtag = { + tags: {}, + tagList: [], + callbacks: {}, + prefix: prefix, + anchor: document.createElement('a'), + mutation: window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver, + tagOptions: { + content: '', + mixins: [], + events: {}, + methods: {}, + getters: {}, + setters: {}, + onCreate: function(){}, + onInsert: function(){} + }, + eventMap: { + animationstart: ['animationstart', 'oAnimationStart', 'MSAnimationStart', 'webkitAnimationStart'], + transitionend: ['transitionend', 'oTransitionEnd', 'MSTransitionEnd', 'webkitTransitionEnd'], + tap: [ 'ontouchend' in document ? 'touchend' : 'mouseup'] + }, + pseudos: { + delegate: { + listener: function(pseudo, fn, args){ + var target = xtag.query(this, pseudo.value).filter(function(node){ + return node == args[0].target || node.contains ? node.contains(args[0].target) : false; + })[0]; + args.splice(args.length, 0, this); + return target ? fn.apply(target, args) : false; + } + }, + preventable: { + listener: function(pseudo, fn, args){ + if (!args[0].defaultPrevented) fn.apply(this, args); + } + }, + attribute: { + onAdd: function(pseudo){ + this.xtag.attributeSetters = this.xtag.attributeSetters || {}; + this.xtag.attributeSetters[pseudo.value] = pseudo.key.split(':')[0]; + }, + listener: function(pseudo, fn, args){ + fn.call(this, args[0]); + this.setAttribute(pseudo.value, args[0], true); + } + }, + touch: { + onAdd: function(pseudo, fn){ + this.addEventListener(touchMap[pseudo.key.split(':')[0]], fn, false); + }, + listener: function(pseudo, fn, args){ + if (fn.touched && args[0].type.match('mouse')) fn.touched = false; + else { + if (args[0].type.match('touch')) fn.touched = true; + args.splice(args.length, 0, this); + fn.apply(this, args); + } + }, + onRemove: function(pseudo, fn){ + this.removeEventListener(touchMap[pseudo.key.split(':')[0]], fn); + } + }, + keystop: keypseudo, + keypass: keypseudo + }, + mixins: { + request: { + onInsert: function(){ + this.src = this.getAttribute('src'); + }, + getters: { + dataready: function(){ + return this.xtag.dataready; + } + }, + setters: { + src: function(src){ + if (src){ + this.setAttribute('src', src); + xtag.request(this, { url: src, method: 'GET' }); + } + }, + dataready: function(fn){ + this.xtag.dataready = fn; + if (this.xtag.request && this.xtag.request.readyState == 4) fn.call(this, this.xtag.request); + } + } + } + }, + + typeOf: function(obj) { + return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase(); + }, + + toArray: function(obj){ + var sliced = Array.prototype.slice.call(obj, 0); + return sliced.hasOwnProperty ? sliced : [obj]; + }, + + hasClass: function(element, className){ + return !!~element.className.split(' ').indexOf(className); + }, + + addClass: function(element, className){ + if (!xtag.hasClass(element, className)){ + var name = element.className; + element.className = name[name.length-1] == ' ' || name.length == 0 ? + name + className : name + " " + className; + } + return element; + }, + + removeClass: function(element, className){ + element.className = element.className.replace(className,''); + return element; + }, + + toggleClass: function(element, className){ + return !xtag.hasClass(element, className) ? xtag.addClass(element,className) : xtag.removeClass(element, className); + }, + + query: function(element, selector){ + return xtag.toArray(element.querySelectorAll(selector)); + }, + + queryChildren: function(element, selector){ + var result = null, + id = 'x-' + new Date().getTime(), + attr = '[xtag-temp-id="' + id + '"] > ', + selector = attr + (selector + '').replace(',', ',' + attr, 'g'); + element.setAttribute('xtag-temp-id', id); + result = element.parentNode.querySelectorAll(selector); + element.removeAttribute('xtag-temp-id'); + return xtag.toArray(result); + }, + + defineProperty: function(element, property, accessor, value){ + return document.documentElement.__defineGetter__ ? function(element, property, accessor, value){ + element['__define' + accessor[0].toUpperCase() + 'etter__'](property, value); + } : function(element, property, accessor, value){ + var obj = { configurable: true }; + obj[accessor] = value; + Object.defineProperty(element, property, obj); + }; + }(), + + clone: function(obj) { + var F = function(){}; + F.prototype = obj; + return new F(); + }, + + merge: function(source, k, v){ + if (xtag.typeOf(k) == 'string') return mergeOne(source, k, v); + for (var i = 1, l = arguments.length; i < l; i++){ + var object = arguments[i]; + for (var key in object) mergeOne(source, key, object[key]); + } + return source; + }, + + wrap: function(original, fn){ + return function(){ + var args = xtag.toArray(arguments); + original.apply(this, args); + fn.apply(this, args); + } + }, + + skipTransition: function(element, fn, bind){ + var duration = prefix.js + 'TransitionDuration'; + element.style[duration] = '0.001s'; + fn.call(bind); + xtag.addEvent(element, 'transitionend', function(){ + element.style[duration] = ''; + }); + }, + + tagCheck: function(element){ + return element.tagName ? xtag.tags[element.tagName.toLowerCase()] : false; + }, + + getOptions: function(element){ + return xtag.tagCheck(element) || xtag.tagOptions; + }, + + register: function(tag, options){ + xtag.tagList.push(tag); + xtag.tags[tag] = xtag.merge({ tagName: tag }, xtag.tagOptions, xtag.applyMixins(options)); + if (xtag.domready) xtag.query(document, tag).forEach(nodeInserted); + }, + + extendElement: function(element, insert){ + if (!element.xtag){ + element.xtag = {}; + var options = xtag.getOptions(element); + for (var z in options.methods) xtag.bindMethods(element, z, options.methods[z]); + for (var z in options.setters) xtag.applyAccessor(element, z, 'set', options.setters[z]); + for (var z in options.getters) xtag.applyAccessor(element, z, 'get', options.getters[z]); + xtag.addEvents(element, options.events, options.eventMap); + if (options.content) element.innerHTML = options.content; + options.onCreate.call(element); + } + }, + + bindMethods: function(element, key, method){ + element.xtag[key] = function(){ return method.apply(element, xtag.toArray(arguments)) }; + }, + + applyMixins: function(options){ + if (options.mixins) options.mixins.forEach(function(name){ + var mixin = xtag.mixins[name]; + for (var z in mixin) { + switch (xtag.typeOf(mixin[z])){ + case 'function': options[z] = options[z] ? xtag.wrap(options[z], mixin[z]) : mixin[z]; + break; + case 'object': options[z] = xtag.merge({}, mixin[z], options[z]); + break; + default: options[z] = mixin[z]; + } + } + }); + return options; + }, + + applyAccessor: function(element, key, accessor, fn){ + xtag.defineProperty(element, key.split(':')[0], accessor, xtag.applyPseudos(element, key, fn)); + }, + + applyPseudos: function(element, key, fn){ + var action = fn, onAdd = {}; + if (key.match(':')){ + key.replace(/:(\w*)(?:\(([^\)]*)\))?/g, function(match, name, value){ + var lastPseudo = action, + pseudo = xtag.pseudos[name], + split = { + key: key, + name: name, + value: value + }; + if (pseudo.onAdd) onAdd[name] = split; + action = function(){ + return pseudo.listener.apply(element, [split, fn, xtag.toArray(arguments)]); + } + }); + for (var z in onAdd) xtag.pseudos[z].onAdd.call(element, onAdd[z], action); + } + return action; + }, + + removePseudos: function(element, key, fn){ + + if (key.match(':')){ + key.replace(/:(\w*)(?:\(([^\)]*)\))?/g, function(match, name, value){ + var lastPseudo = action, + pseudo = xtag.pseudos[name], + split = { + key: key, + name: name, + value: value + }; + if (pseudo.onRemove) pseudo.onRemove.call(element, split, fn); + + }); + + } + }, + + request: function(element, options){ + xtag.clearRequest(element); + var last = element.xtag.request || {}; + element.xtag.request = options; + var request = element.xtag.request, + callbackKey = element.getAttribute('data-callback-key') || 'callback' + '=xtag.callbacks.'; + if (xtag.fireEvent(element, 'beforerequest') === false) return false; + if (last.url && !options.update && last.url.replace(new RegExp('\&?\(' + callbackKey + 'x[0-9]+)'), '') == element.xtag.request.url){ + element.xtag.request = last; + return false; + } + element.setAttribute('src', element.xtag.request.url); + xtag.anchor.href = options.url; + if (xtag.anchor.hostname == window.location.hostname) { + request = xtag.merge(new XMLHttpRequest(), request); + request.onreadystatechange = function(){ + element.setAttribute('data-readystate', request.readyState); + if (request.readyState == 4 && request.status < 400) xtag.requestCallback(element, request); + }; + ['error', 'abort', 'load'].forEach(function(type){ + request['on' + type] = function(event){ + event.request = request; + xtag.fireEvent(element, type, event); + } + }); + request.open(request.method , request.url, true); + request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + request.send(); + } + else { + var callbackID = request.callbackID = 'x' + new Date().getTime(); + element.setAttribute('data-readystate', request.readyState = 0); + xtag.callbacks[callbackID] = function(data){ + request.status = 200; + request.readyState = 4; + request.responseText = data; + xtag.requestCallback(element, request); + delete xtag.callbacks[callbackID]; + xtag.clearRequest(element); + } + request.script = document.createElement('script'); + request.script.type = 'text/javascript'; + request.script.src = options.url = options.url + (~options.url.indexOf('?') ? '&' : '?') + callbackKey + callbackID; + request.script.onerror = function(error){ + element.setAttribute('data-readystate', request.readyState = 4); + element.setAttribute('data-requeststatus', request.status = 400); + xtag.fireEvent(element, 'error', error); + } + head.appendChild(request.script); + } + element.xtag.request = request; + }, + + requestCallback: function(element, request){ + if (request != element.xtag.request) return xtag; + element.setAttribute('data-readystate', request.readyState); + element.setAttribute('data-requeststatus', request.status); + xtag.fireEvent(element, 'dataready', { request: request }); + if (element.dataready) element.dataready.call(element, request); + }, + + clearRequest: function(element){ + var request = element.xtag.request; + if (!request) return xtag; + if (request.script && ~xtag.toArray(head.children).indexOf(request.script)) { + head.removeChild(request.script); + } + else if (request.abort) request.abort(); + }, + + addEvent: function(element, type, fn, map){ + var eventKey = type.split(':')[0], + eventMap = (map || xtag.eventMap || {})[eventKey] || [eventKey]; + var wrapped = xtag.applyPseudos(element, type, fn); + eventMap.forEach(function(name){ + element.addEventListener(name, wrapped, !!~['focus', 'blur'].indexOf(name)); + }); + return wrapped; + }, + + addEvents: function(element, events, map){ + for (var z in events) xtag.addEvent(element, z, events[z], map); + }, + + removeEvent: function(element, type, fn){ + var eventKey = type.split(':')[0], + eventMap = (xtag.eventMap || {})[eventKey] || [eventKey]; + eventMap.forEach(function(name){ + element.removeEventListener(name, fn); + }); + }, + + fireEvent: function(element, type, data){ + var event = document.createEvent('Event'); + event.initEvent(type, true, true); + element.dispatchEvent(xtag.merge(event, data)); + }, + + observe: function(element, fn){ + if (xtag.mutation){ + var mutation = new xtag.mutation(function(mutations) { + var added = []; + mutations.forEach(function(record){ + var nodes = record.addedNodes, length = nodes.length; + for (i = 0; i < length && added.indexOf(nodes[i]) == -1; i++){ + added.push(nodes[i]); + fn(nodes[i], true); + } + }); + }); + mutation.observe(element, { + subtree: true, + childList: true, + attributes: !true, + characterData: false + }); + } + else element.addEventListener('DOMNodeInserted', function(event){ + fn(event.target); + }, false); + } + }; + + var setAttribute = HTMLElement.prototype.setAttribute; + HTMLElement.prototype.setAttribute = function(attr, value, setter){ + if (!setter && this.xtag && this.xtag.attributeSetters) this[this.xtag.attributeSetters[attr]] = value; + setAttribute.call(this, attr, value); + }; + + var createElement = document.createElement; + document.createElement = function(tag){ + var element = createElement.call(this, tag); + if (xtag.tagCheck(element)) xtag.extendElement(element); + return element; + }; + + document.addEventListener('DOMContentLoaded', function(event){ + xtag.observe(document.documentElement, nodeInserted); + if (xtag.tagList[0]) xtag.query(document, xtag.tagList).forEach(function(element){ + nodeInserted(element); + }); + xtag.domready = true; + xtag.fireEvent(document, 'DOMComponentsLoaded'); + }, false); + +})(); diff --git a/mkt/asset_bundles.py b/mkt/asset_bundles.py index 4d1fa746208..40f30487924 100644 --- a/mkt/asset_bundles.py +++ b/mkt/asset_bundles.py @@ -109,7 +109,14 @@ ), 'mkt/ecosystem': ( 'css/ecosystem/landing.less', + 'css/ecosystem/documentation.less', 'css/ecosystem/footer.less', + 'css/ecosystem/xtags/alert-popup.css', + 'css/ecosystem/xtags/dialog-toast.css', + 'css/ecosystem/xtags/listview.css', + 'css/ecosystem/xtags/slidebox.css', + 'css/ecosystem/xtags/slider.css', + 'css/ecosystem/xtags/tabbox.css', ), 'mkt/in-app-payments': ( 'css/mkt/reset.less', @@ -293,4 +300,13 @@ 'js/impala/suggestions.js', 'js/mkt/lookup-tool.js', ), + 'mkt/xtags': ( + 'js/mkt/xtags/x-tag.js', + 'js/mkt/xtags/alert-popup.js', + 'js/mkt/xtags/dialog-toast.js', + 'js/mkt/xtags/listview.js', + 'js/mkt/xtags/slidebox.js', + 'js/mkt/xtags/slider.js', + 'js/mkt/xtags/tabbox.js', + ), } diff --git a/mkt/ecosystem/fixtures/ecosystem/mdncache-item.json b/mkt/ecosystem/fixtures/ecosystem/mdncache-item.json index 247d8b677b7..9ca137cf418 100644 --- a/mkt/ecosystem/fixtures/ecosystem/mdncache-item.json +++ b/mkt/ecosystem/fixtures/ecosystem/mdncache-item.json @@ -4,7 +4,7 @@ "model": "ecosystem.mdncache", "fields": { "name": "old", - "locale": "en", + "locale": "en-US", "created": "2011-05-01 09:31:46", "modified": "2011-05-01 09:31:46" } @@ -13,11 +13,22 @@ "pk": 2, "model": "ecosystem.mdncache", "fields": { - "name": "apps", - "locale": "en", + "name": "html5", + "locale": "en-US", "title": "Applications Tutorial", - "toc": "
  1. 1. Design
  2. 2. Code
  3. 3. Test
  4. 4. Publish
  5. 5. Maintain
", - "content": "

DRAFT
This page is not complete.

Design

 

Code

 

Test

 

Publish

 

Maintain

", + "content": "DRAFT", + "created": "2011-05-01 09:31:46", + "modified": "2011-05-01 09:31:46" + } + }, + { + "pk": 3, + "model": "ecosystem.mdncache", + "fields": { + "name": "design_principles", + "locale": "en-US", + "title": "Design Principles", + "content": "DRAFT", "created": "2011-05-01 09:31:46", "modified": "2011-05-01 09:31:46" } diff --git a/mkt/ecosystem/tasks.py b/mkt/ecosystem/tasks.py index 4a489740ac3..10ac6c73bbb 100644 --- a/mkt/ecosystem/tasks.py +++ b/mkt/ecosystem/tasks.py @@ -8,8 +8,6 @@ import bleach from celeryutils import task import commonware.log -from lxml import etree -from pyquery import PyQuery from models import MdnCache @@ -49,9 +47,44 @@ tutorials = [ { - 'title': 'Apps Tutorial', - 'name': 'apps', - 'mdn': 'https://developer.mozilla.org/%(locale)s/Apps/Tracks/General' + 'title': 'Introduction to HTML5', + 'name': 'html5', + 'mdn': 'https://developer.mozilla.org/%(locale)s/docs/HTML/HTML5/Introduction_to_HTML5?raw=1¯os=true' + }, + { + 'title': 'Manifests', + 'name': 'manifests', + 'mdn': 'https://developer.mozilla.org/%(locale)s/docs/Apps/Manifest?raw=1¯os=true' + }, + { + 'title': 'Manifest FAQ', + 'name': 'manifest_faq', + 'mdn': 'https://developer.mozilla.org/%(locale)s/docs/Apps/FAQs/About_app_manifests?raw=1¯os=true' + }, + { + 'title': 'Design Guidelines', + 'name': 'design_guidelines', + 'mdn': 'https://developer.mozilla.org/%(locale)s/docs/Apps/Design_Guidelines?raw=1¯os=true' + }, + { + 'title': 'Design Principles', + 'name': 'design_principles', + 'mdn': 'https://developer.mozilla.org/%(locale)s/docs/Apps/Design_Guidelines/Design_Principles?raw=1¯os=true' + }, + { + 'title': 'Purpose of your App', + 'name': 'purpose_of_your_app', + 'mdn': 'https://developer.mozilla.org/%(locale)s/docs/Apps/Design_Guidelines/Purpose_of_your_app?raw=1¯os=true' + }, + { + 'title': 'Design Patterns', + 'name': 'design_patterns', + 'mdn': 'https://developer.mozilla.org/%(locale)s/docs/Apps/Design_Guidelines/Design_patterns?raw=1¯os=true' + }, + { + 'title': 'References', + 'name': 'references', + 'mdn': 'https://developer.mozilla.org/%(locale)s/docs/Apps/Design_Guidelines/References?raw=1¯os=true' }, ] @@ -59,7 +92,7 @@ # locale, we are going to try each locale in this array for each tutorial # page entry. We may get some 404s, but that's ok if some translations # are not finished yet. We grab the ones that are completed. -locales = ['en'] +locales = ['en-US'] @task @@ -83,7 +116,7 @@ def _update_mdn_items(items): log.info('Fetching MDN article "%s": %s' % (name, url)) try: - toc, content = _fetch_mdn_page(url) + content = _fetch_mdn_page(url) except Http404: log.error(u'404 on MDN article "%s": %s' % (name, url)) continue @@ -96,7 +129,6 @@ def _update_mdn_items(items): name=item['name'], locale=locale) model.title = item['title'] - model.toc = toc model.content = content model.permalink = url model.save() @@ -107,24 +139,14 @@ def _update_mdn_items(items): def _fetch_mdn_page(url): - data = bleach.clean(_get_page(url), attributes=ALLOWED_ATTRIBUTES, + return bleach.clean(_get_page(url), attributes=ALLOWED_ATTRIBUTES, tags=ALLOWED_TAGS, strip_comments=False) - root = PyQuery(data) - toc = root.find('#article-nav div.page-toc ol')[0] - content = root.find('#pageText')[0] - - toc.set('id', 'mdn-toc') - content.set('id', 'mdn-content') - - return (etree.tostring(toc, pretty_print=True), - etree.tostring(content, pretty_print=True)) - def _get_page(url): try: return urllib2.urlopen(url).read() - except URLError as e: + except urllib2.URLError as e: if e.code == 404: raise Http404 else: diff --git a/mkt/ecosystem/templates/ecosystem/base.html b/mkt/ecosystem/templates/ecosystem/base.html index f509b0605ab..6d16d4ee2b0 100644 --- a/mkt/ecosystem/templates/ecosystem/base.html +++ b/mkt/ecosystem/templates/ecosystem/base.html @@ -6,11 +6,32 @@ {% endblock %} {% block siteheader %} - {% include 'ecosystem/header.html' %} + {% endblock %} {% block sitefooter %} -