Jdlrobson has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/332926 )
Change subject: Icon moved to precompiled mobile.frontend module ...................................................................... Icon moved to precompiled mobile.frontend module Change-Id: If9dca17ecfecc385928ba326e39134cfbdb32f72 --- R build_resources/mobile.frontend/Icon.js M build_resources/mobile.frontend/index.js R build_resources/mobile.frontend/templates/icon.hogan M extension.json M package.json M resources/mobile.drawers/CtaDrawer.js M resources/mobile.drawers/Drawer.js M resources/mobile.editor.common/EditorOverlayBase.js M resources/mobile.frontend/index.js M resources/mobile.issues/CleanupOverlay.js M resources/mobile.mediaViewer/ImageOverlay.js M resources/mobile.overlays/Overlay.js M resources/mobile.patrol.ajax/init.js M resources/mobile.references/ReferencesDrawer.js M resources/mobile.search/SearchOverlay.js M resources/mobile.special.nearby.scripts/nearby.js M resources/mobile.startup/icons.js M resources/mobile.talk.overlays/TalkSectionAddOverlay.js M resources/mobile.toc/TableOfContents.js M resources/mobile.toggle/toggle.js M resources/mobile.watchstar/Watchstar.js M resources/skins.minerva.editor/init.js M tests/qunit/mobile.pagelist.scripts/test_WatchstarPageList.js M tests/qunit/mobile.watchlist/test_WatchList.js M tests/qunit/mobile.watchstar/test_Watchstar.js M webpack.config.js 26 files changed, 952 insertions(+), 49 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MobileFrontend refs/changes/26/332926/1 diff --git a/resources/mobile.startup/Icon.js b/build_resources/mobile.frontend/Icon.js similarity index 93% rename from resources/mobile.startup/Icon.js rename to build_resources/mobile.frontend/Icon.js index 0cdba11..15728b8 100644 --- a/resources/mobile.startup/Icon.js +++ b/build_resources/mobile.frontend/Icon.js @@ -1,6 +1,6 @@ ( function ( M, $ ) { - var View = mw.mf.View; + var View = require( './View.js' ); /** * A wrapper for creating an icon. @@ -70,9 +70,9 @@ toHtmlString: function () { return $( '<div>' ).append( this.$el ).html(); }, - template: mw.template.get( 'mobile.startup', 'icon.hogan' ) + template: require( './templates/icon.hogan' ) } ); - M.define( 'mobile.startup/Icon', Icon ); + module.exports = Icon; }( mw.mobileFrontend, jQuery ) ); diff --git a/build_resources/mobile.frontend/index.js b/build_resources/mobile.frontend/index.js index 08acc21..d99043d 100644 --- a/build_resources/mobile.frontend/index.js +++ b/build_resources/mobile.frontend/index.js @@ -1,5 +1,6 @@ module.exports = mediaWiki.mf = { Browser: require( './Browser' ), + Icon: require( './Icon' ), View: require( './View' ), util: require( './util.js' ) }; diff --git a/resources/mobile.startup/icon.hogan b/build_resources/mobile.frontend/templates/icon.hogan similarity index 100% rename from resources/mobile.startup/icon.hogan rename to build_resources/mobile.frontend/templates/icon.hogan diff --git a/extension.json b/extension.json index 3d10e29..f95320f 100644 --- a/extension.json +++ b/extension.json @@ -557,7 +557,6 @@ ], "templates": { "anchor.hogan": "resources/mobile.startup/anchor.hogan", - "icon.hogan": "resources/mobile.startup/icon.hogan", "Section.hogan": "resources/mobile.startup/Section.hogan", "button.hogan": "resources/mobile.startup/button.hogan" }, @@ -574,7 +573,6 @@ "resources/mobile.startup/PageGateway.js", "resources/mobile.startup/Anchor.js", "resources/mobile.startup/Button.js", - "resources/mobile.startup/Icon.js", "resources/mobile.startup/icons.js", "resources/mobile.startup/Panel.js", "resources/mobile.startup/Section.js", diff --git a/package.json b/package.json index 0234171..4202945 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,25 @@ { - "private": true, - "scripts": { - "test": "grunt test && npm run doc", - "build": "webpack", - "predoc": "bundle install --path vendor/bundle", - "doc": "bundle exec jsduck" - }, - "dependencies": { - "jsdoc": "3.4.2", - "svgo": ">=0.4.4" - }, - "devDependencies": { - "eslint-config-wikimedia": "0.3.0", - "grunt": "^1.0.1", - "grunt-banana-checker": "^0.5.0", - "grunt-contrib-watch": "^1.0.0", - "grunt-eslint": "19.0.0", - "grunt-jsonlint": "^1.1.0", - "grunt-notify": "^0.4.5", - "grunt-stylelint": "^0.6.0", - "stylelint-config-wikimedia": "^0.3.0" - } + "private": true, + "scripts": { + "test": "grunt test && npm run doc", + "build": "webpack", + "predoc": "bundle install --path vendor/bundle", + "doc": "bundle exec jsduck" + }, + "dependencies": { + "jsdoc": "3.4.2", + "svgo": ">=0.4.4" + }, + "devDependencies": { + "eslint-config-wikimedia": "0.3.0", + "grunt": "^1.0.1", + "grunt-banana-checker": "^0.5.0", + "grunt-contrib-watch": "^1.0.0", + "grunt-eslint": "19.0.0", + "grunt-jsonlint": "^1.1.0", + "grunt-notify": "^0.4.5", + "grunt-stylelint": "^0.6.0", + "mustache-loader": "^0.4.1", + "stylelint-config-wikimedia": "^0.3.0" + } } diff --git a/resources/mobile.drawers/CtaDrawer.js b/resources/mobile.drawers/CtaDrawer.js index b57f80c..bf80694 100644 --- a/resources/mobile.drawers/CtaDrawer.js +++ b/resources/mobile.drawers/CtaDrawer.js @@ -1,6 +1,6 @@ ( function ( M, $ ) { var Drawer = M.require( 'mobile.drawers/Drawer' ), - Icon = M.require( 'mobile.startup/Icon' ), + Icon = mw.mf.Icon, Button = M.require( 'mobile.startup/Button' ), Anchor = M.require( 'mobile.startup/Anchor' ); diff --git a/resources/mobile.drawers/Drawer.js b/resources/mobile.drawers/Drawer.js index 2049133..db9969c 100644 --- a/resources/mobile.drawers/Drawer.js +++ b/resources/mobile.drawers/Drawer.js @@ -1,7 +1,7 @@ ( function ( M, $ ) { var Panel = M.require( 'mobile.startup/Panel' ), - Icon = M.require( 'mobile.startup/Icon' ); + Icon = mw.mf.Icon; /** * A {@link View} that pops up from the bottom of the screen. diff --git a/resources/mobile.editor.common/EditorOverlayBase.js b/resources/mobile.editor.common/EditorOverlayBase.js index 48032fd..1b6c239 100644 --- a/resources/mobile.editor.common/EditorOverlayBase.js +++ b/resources/mobile.editor.common/EditorOverlayBase.js @@ -2,7 +2,7 @@ var Overlay = M.require( 'mobile.overlays/Overlay' ), PageGateway = M.require( 'mobile.startup/PageGateway' ), browser = mw.mf.Browser.getSingleton(), - Icon = M.require( 'mobile.startup/Icon' ), + Icon = mw.mf.Icon, toast = M.require( 'mobile.toast/toast' ), user = M.require( 'mobile.user/user' ); diff --git a/resources/mobile.frontend/index.js b/resources/mobile.frontend/index.js index f657690..e7641f8 100644 --- a/resources/mobile.frontend/index.js +++ b/resources/mobile.frontend/index.js @@ -46,8 +46,9 @@ module.exports = mediaWiki.mf = { Browser: __webpack_require__( 1 ), - View: __webpack_require__( 2 ), - util: __webpack_require__( 3 ) + Icon: __webpack_require__( 2 ), + View: __webpack_require__( 3 ), + util: __webpack_require__( 8 ) }; @@ -268,6 +269,90 @@ /***/ }, /* 2 */ +/***/ function(module, exports, __webpack_require__) { + + ( function ( M, $ ) { + + var View = __webpack_require__( 3 ); + + /** + * A wrapper for creating an icon. + * @class Icon + * @extends View + * + * @constructor + * @param {Object} options Configuration options + */ + function Icon( options ) { + if ( options.hasText ) { + options.modifier = 'mw-ui-icon-before'; + } + if ( options.href ) { + options.tagName = 'a'; + } + View.call( this, options ); + } + + OO.mfExtend( Icon, View, { + /** @inheritdoc */ + isTemplateMode: true, + /** + * @cfg {Object} defaults Default options hash. + * @cfg {boolean} defaults.hasText Whether the icon has text. + * @cfg {boolean} defaults.isSmall Whether the icon should be small. + * @cfg {string} [defaults.href] value of href attribute, when set tagName will default to anchor tag + * @cfg {string} defaults.tagName The name of the tag in which the icon is wrapped. Defaults to 'a' when href option present. + * @cfg {string} defaults.base String used as a base for generating class names. + * Defaults to 'mw-ui-icon'. + * @cfg {string} defaults.name Name of the icon. + * @cfg {string} defaults.modifier Additional class name. + * Defaults to 'mw-ui-icon-element'. + * @cfg {string} defaults.title Tooltip text. + */ + defaults: { + hasText: false, + href: undefined, + tagName: 'div', + isSmall: false, + base: 'mw-ui-icon', + name: '', + modifier: 'mw-ui-icon-element', + title: '' + }, + /** + * Return the full class name that is required for the icon to render + * @method + * @return {string} + */ + getClassName: function () { + return this.$el.attr( 'class' ); + }, + /** + * Return the class that relates to the icon glyph + * @method + * @return {string} + */ + getGlyphClassName: function () { + return this.options.base + '-' + this.options.name; + }, + /** + * Return the HTML representation of this view + * @method + * @return {string} + */ + toHtmlString: function () { + return $( '<div>' ).append( this.$el ).html(); + }, + template: __webpack_require__( 4 ) + } ); + + module.exports = Icon; + + }( mw.mobileFrontend, jQuery ) ); + + +/***/ }, +/* 3 */ /***/ function(module, exports) { var @@ -630,7 +715,817 @@ /***/ }, -/* 3 */ +/* 4 */ +/***/ function(module, exports, __webpack_require__) { + + var H = __webpack_require__(5); + module.exports = function() { var T = new H.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<");t.b(t.v(t.f("tagName",c,p,0)));t.b(" class=\"");t.b(t.v(t.f("base",c,p,0)));t.b(" ");t.b(t.v(t.f("base",c,p,0)));t.b("-");t.b(t.v(t.f("name",c,p,0)));t.b(" ");t.b(t.v(t.f("modifier",c,p,0)));t.b(" ");if(t.s(t.f("isSmall",c,p,1),c,p,0,72,88,"{{ }}")){t.rs(c,p,function(c,p,t){t.b("mw-ui-icon-small");});c.pop();}t.b(" ");t.b(t.v(t.f("additionalClassNames",c,p,0)));t.b("\"");t.b("\n" + i);t.b(" ");if(t.s(t.f("id",c,p,1),c,p,0,135,146,"{{ }}")){t.rs(c,p,function(c,p,t){t.b("id=\"");t.b(t.v(t.f("id",c,p,0)));t.b("\"");});c.pop();}t.b("\n" + i);t.b(" ");if(t.s(t.f("href",c,p,1),c,p,0,164,179,"{{ }}")){t.rs(c,p,function(c,p,t){t.b("href=\"");t.b(t.v(t.f("href",c,p,0)));t.b("\"");});c.pop();}t.b("\n" + i);t.b(" ");if(t.s(t.f("title",c,p,1),c,p,0,200,217,"{{ }}")){t.rs(c,p,function(c,p,t){t.b("title=\"");t.b(t.v(t.f("title",c,p,0)));t.b("\"");});c.pop();}t.b(">");t.b(t.v(t.f("label",c,p,0)));t.b("</");t.b(t.v(t.f("tagName",c,p,0)));t.b(">");t.b("\n");return t.fl(); },partials: {}, subs: { }}, "<{{tagName}} class=\"{{base}} {{base}}-{{name}} {{modifier}} {{#isSmall}}mw-ui-icon-small{{/isSmall}} {{additionalClassNames}}\"\n\t{{#id}}id=\"{{id}}\"{{/id}}\n\t{{#href}}href=\"{{href}}\"{{/href}}\n\t{{#title}}title=\"{{title}}\"{{/title}}>{{label}}</{{tagName}}>\n", H);return T; }(); + +/***/ }, +/* 5 */ +/***/ function(module, exports, __webpack_require__) { + + /* + * Copyright 2011 Twitter, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + // This file is for use with Node.js. See dist/ for browser files. + + var Hogan = __webpack_require__(6); + Hogan.Template = __webpack_require__(7).Template; + Hogan.template = Hogan.Template; + module.exports = Hogan; + + +/***/ }, +/* 6 */ +/***/ function(module, exports, __webpack_require__) { + + /* + * Copyright 2011 Twitter, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + (function (Hogan) { + // Setup regex assignments + // remove whitespace according to Mustache spec + var rIsWhitespace = /\S/, + rQuot = /\"/g, + rNewline = /\n/g, + rCr = /\r/g, + rSlash = /\\/g, + rLineSep = /\u2028/, + rParagraphSep = /\u2029/; + + Hogan.tags = { + '#': 1, '^': 2, '<': 3, '$': 4, + '/': 5, '!': 6, '>': 7, '=': 8, '_v': 9, + '{': 10, '&': 11, '_t': 12 + }; + + Hogan.scan = function scan(text, delimiters) { + var len = text.length, + IN_TEXT = 0, + IN_TAG_TYPE = 1, + IN_TAG = 2, + state = IN_TEXT, + tagType = null, + tag = null, + buf = '', + tokens = [], + seenTag = false, + i = 0, + lineStart = 0, + otag = '{{', + ctag = '}}'; + + function addBuf() { + if (buf.length > 0) { + tokens.push({tag: '_t', text: new String(buf)}); + buf = ''; + } + } + + function lineIsWhitespace() { + var isAllWhitespace = true; + for (var j = lineStart; j < tokens.length; j++) { + isAllWhitespace = + (Hogan.tags[tokens[j].tag] < Hogan.tags['_v']) || + (tokens[j].tag == '_t' && tokens[j].text.match(rIsWhitespace) === null); + if (!isAllWhitespace) { + return false; + } + } + + return isAllWhitespace; + } + + function filterLine(haveSeenTag, noNewLine) { + addBuf(); + + if (haveSeenTag && lineIsWhitespace()) { + for (var j = lineStart, next; j < tokens.length; j++) { + if (tokens[j].text) { + if ((next = tokens[j+1]) && next.tag == '>') { + // set indent to token value + next.indent = tokens[j].text.toString() + } + tokens.splice(j, 1); + } + } + } else if (!noNewLine) { + tokens.push({tag:'\n'}); + } + + seenTag = false; + lineStart = tokens.length; + } + + function changeDelimiters(text, index) { + var close = '=' + ctag, + closeIndex = text.indexOf(close, index), + delimiters = trim( + text.substring(text.indexOf('=', index) + 1, closeIndex) + ).split(' '); + + otag = delimiters[0]; + ctag = delimiters[delimiters.length - 1]; + + return closeIndex + close.length - 1; + } + + if (delimiters) { + delimiters = delimiters.split(' '); + otag = delimiters[0]; + ctag = delimiters[1]; + } + + for (i = 0; i < len; i++) { + if (state == IN_TEXT) { + if (tagChange(otag, text, i)) { + --i; + addBuf(); + state = IN_TAG_TYPE; + } else { + if (text.charAt(i) == '\n') { + filterLine(seenTag); + } else { + buf += text.charAt(i); + } + } + } else if (state == IN_TAG_TYPE) { + i += otag.length - 1; + tag = Hogan.tags[text.charAt(i + 1)]; + tagType = tag ? text.charAt(i + 1) : '_v'; + if (tagType == '=') { + i = changeDelimiters(text, i); + state = IN_TEXT; + } else { + if (tag) { + i++; + } + state = IN_TAG; + } + seenTag = i; + } else { + if (tagChange(ctag, text, i)) { + tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag, + i: (tagType == '/') ? seenTag - otag.length : i + ctag.length}); + buf = ''; + i += ctag.length - 1; + state = IN_TEXT; + if (tagType == '{') { + if (ctag == '}}') { + i++; + } else { + cleanTripleStache(tokens[tokens.length - 1]); + } + } + } else { + buf += text.charAt(i); + } + } + } + + filterLine(seenTag, true); + + return tokens; + } + + function cleanTripleStache(token) { + if (token.n.substr(token.n.length - 1) === '}') { + token.n = token.n.substring(0, token.n.length - 1); + } + } + + function trim(s) { + if (s.trim) { + return s.trim(); + } + + return s.replace(/^\s*|\s*$/g, ''); + } + + function tagChange(tag, text, index) { + if (text.charAt(index) != tag.charAt(0)) { + return false; + } + + for (var i = 1, l = tag.length; i < l; i++) { + if (text.charAt(index + i) != tag.charAt(i)) { + return false; + } + } + + return true; + } + + // the tags allowed inside super templates + var allowedInSuper = {'_t': true, '\n': true, '$': true, '/': true}; + + function buildTree(tokens, kind, stack, customTags) { + var instructions = [], + opener = null, + tail = null, + token = null; + + tail = stack[stack.length - 1]; + + while (tokens.length > 0) { + token = tokens.shift(); + + if (tail && tail.tag == '<' && !(token.tag in allowedInSuper)) { + throw new Error('Illegal content in < super tag.'); + } + + if (Hogan.tags[token.tag] <= Hogan.tags['$'] || isOpener(token, customTags)) { + stack.push(token); + token.nodes = buildTree(tokens, token.tag, stack, customTags); + } else if (token.tag == '/') { + if (stack.length === 0) { + throw new Error('Closing tag without opener: /' + token.n); + } + opener = stack.pop(); + if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) { + throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n); + } + opener.end = token.i; + return instructions; + } else if (token.tag == '\n') { + token.last = (tokens.length == 0) || (tokens[0].tag == '\n'); + } + + instructions.push(token); + } + + if (stack.length > 0) { + throw new Error('missing closing tag: ' + stack.pop().n); + } + + return instructions; + } + + function isOpener(token, tags) { + for (var i = 0, l = tags.length; i < l; i++) { + if (tags[i].o == token.n) { + token.tag = '#'; + return true; + } + } + } + + function isCloser(close, open, tags) { + for (var i = 0, l = tags.length; i < l; i++) { + if (tags[i].c == close && tags[i].o == open) { + return true; + } + } + } + + function stringifySubstitutions(obj) { + var items = []; + for (var key in obj) { + items.push('"' + esc(key) + '": function(c,p,t,i) {' + obj[key] + '}'); + } + return "{ " + items.join(",") + " }"; + } + + function stringifyPartials(codeObj) { + var partials = []; + for (var key in codeObj.partials) { + partials.push('"' + esc(key) + '":{name:"' + esc(codeObj.partials[key].name) + '", ' + stringifyPartials(codeObj.partials[key]) + "}"); + } + return "partials: {" + partials.join(",") + "}, subs: " + stringifySubstitutions(codeObj.subs); + } + + Hogan.stringify = function(codeObj, text, options) { + return "{code: function (c,p,i) { " + Hogan.wrapMain(codeObj.code) + " }," + stringifyPartials(codeObj) + "}"; + } + + var serialNo = 0; + Hogan.generate = function(tree, text, options) { + serialNo = 0; + var context = { code: '', subs: {}, partials: {} }; + Hogan.walk(tree, context); + + if (options.asString) { + return this.stringify(context, text, options); + } + + return this.makeTemplate(context, text, options); + } + + Hogan.wrapMain = function(code) { + return 'var t=this;t.b(i=i||"");' + code + 'return t.fl();'; + } + + Hogan.template = Hogan.Template; + + Hogan.makeTemplate = function(codeObj, text, options) { + var template = this.makePartials(codeObj); + template.code = new Function('c', 'p', 'i', this.wrapMain(codeObj.code)); + return new this.template(template, text, this, options); + } + + Hogan.makePartials = function(codeObj) { + var key, template = {subs: {}, partials: codeObj.partials, name: codeObj.name}; + for (key in template.partials) { + template.partials[key] = this.makePartials(template.partials[key]); + } + for (key in codeObj.subs) { + template.subs[key] = new Function('c', 'p', 't', 'i', codeObj.subs[key]); + } + return template; + } + + function esc(s) { + return s.replace(rSlash, '\\\\') + .replace(rQuot, '\\\"') + .replace(rNewline, '\\n') + .replace(rCr, '\\r') + .replace(rLineSep, '\\u2028') + .replace(rParagraphSep, '\\u2029'); + } + + function chooseMethod(s) { + return (~s.indexOf('.')) ? 'd' : 'f'; + } + + function createPartial(node, context) { + var prefix = "<" + (context.prefix || ""); + var sym = prefix + node.n + serialNo++; + context.partials[sym] = {name: node.n, partials: {}}; + context.code += 't.b(t.rp("' + esc(sym) + '",c,p,"' + (node.indent || '') + '"));'; + return sym; + } + + Hogan.codegen = { + '#': function(node, context) { + context.code += 'if(t.s(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,1),' + + 'c,p,0,' + node.i + ',' + node.end + ',"' + node.otag + " " + node.ctag + '")){' + + 't.rs(c,p,' + 'function(c,p,t){'; + Hogan.walk(node.nodes, context); + context.code += '});c.pop();}'; + }, + + '^': function(node, context) { + context.code += 'if(!t.s(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,1),c,p,1,0,0,"")){'; + Hogan.walk(node.nodes, context); + context.code += '};'; + }, + + '>': createPartial, + '<': function(node, context) { + var ctx = {partials: {}, code: '', subs: {}, inPartial: true}; + Hogan.walk(node.nodes, ctx); + var template = context.partials[createPartial(node, context)]; + template.subs = ctx.subs; + template.partials = ctx.partials; + }, + + '$': function(node, context) { + var ctx = {subs: {}, code: '', partials: context.partials, prefix: node.n}; + Hogan.walk(node.nodes, ctx); + context.subs[node.n] = ctx.code; + if (!context.inPartial) { + context.code += 't.sub("' + esc(node.n) + '",c,p,i);'; + } + }, + + '\n': function(node, context) { + context.code += write('"\\n"' + (node.last ? '' : ' + i')); + }, + + '_v': function(node, context) { + context.code += 't.b(t.v(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,0)));'; + }, + + '_t': function(node, context) { + context.code += write('"' + esc(node.text) + '"'); + }, + + '{': tripleStache, + + '&': tripleStache + } + + function tripleStache(node, context) { + context.code += 't.b(t.t(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,0)));'; + } + + function write(s) { + return 't.b(' + s + ');'; + } + + Hogan.walk = function(nodelist, context) { + var func; + for (var i = 0, l = nodelist.length; i < l; i++) { + func = Hogan.codegen[nodelist[i].tag]; + func && func(nodelist[i], context); + } + return context; + } + + Hogan.parse = function(tokens, text, options) { + options = options || {}; + return buildTree(tokens, '', [], options.sectionTags || []); + } + + Hogan.cache = {}; + + Hogan.cacheKey = function(text, options) { + return [text, !!options.asString, !!options.disableLambda, options.delimiters, !!options.modelGet].join('||'); + } + + Hogan.compile = function(text, options) { + options = options || {}; + var key = Hogan.cacheKey(text, options); + var template = this.cache[key]; + + if (template) { + var partials = template.partials; + for (var name in partials) { + delete partials[name].instance; + } + return template; + } + + template = this.generate(this.parse(this.scan(text, options.delimiters), text, options), text, options); + return this.cache[key] = template; + } + })( true ? exports : Hogan); + + +/***/ }, +/* 7 */ +/***/ function(module, exports, __webpack_require__) { + + /* + * Copyright 2011 Twitter, Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + var Hogan = {}; + + (function (Hogan) { + Hogan.Template = function (codeObj, text, compiler, options) { + codeObj = codeObj || {}; + this.r = codeObj.code || this.r; + this.c = compiler; + this.options = options || {}; + this.text = text || ''; + this.partials = codeObj.partials || {}; + this.subs = codeObj.subs || {}; + this.buf = ''; + } + + Hogan.Template.prototype = { + // render: replaced by generated code. + r: function (context, partials, indent) { return ''; }, + + // variable escaping + v: hoganEscape, + + // triple stache + t: coerceToString, + + render: function render(context, partials, indent) { + return this.ri([context], partials || {}, indent); + }, + + // render internal -- a hook for overrides that catches partials too + ri: function (context, partials, indent) { + return this.r(context, partials, indent); + }, + + // ensurePartial + ep: function(symbol, partials) { + var partial = this.partials[symbol]; + + // check to see that if we've instantiated this partial before + var template = partials[partial.name]; + if (partial.instance && partial.base == template) { + return partial.instance; + } + + if (typeof template == 'string') { + if (!this.c) { + throw new Error("No compiler available."); + } + template = this.c.compile(template, this.options); + } + + if (!template) { + return null; + } + + // We use this to check whether the partials dictionary has changed + this.partials[symbol].base = template; + + if (partial.subs) { + // Make sure we consider parent template now + if (!partials.stackText) partials.stackText = {}; + for (key in partial.subs) { + if (!partials.stackText[key]) { + partials.stackText[key] = (this.activeSub !== undefined && partials.stackText[this.activeSub]) ? partials.stackText[this.activeSub] : this.text; + } + } + template = createSpecializedPartial(template, partial.subs, partial.partials, + this.stackSubs, this.stackPartials, partials.stackText); + } + this.partials[symbol].instance = template; + + return template; + }, + + // tries to find a partial in the current scope and render it + rp: function(symbol, context, partials, indent) { + var partial = this.ep(symbol, partials); + if (!partial) { + return ''; + } + + return partial.ri(context, partials, indent); + }, + + // render a section + rs: function(context, partials, section) { + var tail = context[context.length - 1]; + + if (!isArray(tail)) { + section(context, partials, this); + return; + } + + for (var i = 0; i < tail.length; i++) { + context.push(tail[i]); + section(context, partials, this); + context.pop(); + } + }, + + // maybe start a section + s: function(val, ctx, partials, inverted, start, end, tags) { + var pass; + + if (isArray(val) && val.length === 0) { + return false; + } + + if (typeof val == 'function') { + val = this.ms(val, ctx, partials, inverted, start, end, tags); + } + + pass = !!val; + + if (!inverted && pass && ctx) { + ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]); + } + + return pass; + }, + + // find values with dotted names + d: function(key, ctx, partials, returnFound) { + var found, + names = key.split('.'), + val = this.f(names[0], ctx, partials, returnFound), + doModelGet = this.options.modelGet, + cx = null; + + if (key === '.' && isArray(ctx[ctx.length - 2])) { + val = ctx[ctx.length - 1]; + } else { + for (var i = 1; i < names.length; i++) { + found = findInScope(names[i], val, doModelGet); + if (found !== undefined) { + cx = val; + val = found; + } else { + val = ''; + } + } + } + + if (returnFound && !val) { + return false; + } + + if (!returnFound && typeof val == 'function') { + ctx.push(cx); + val = this.mv(val, ctx, partials); + ctx.pop(); + } + + return val; + }, + + // find values with normal names + f: function(key, ctx, partials, returnFound) { + var val = false, + v = null, + found = false, + doModelGet = this.options.modelGet; + + for (var i = ctx.length - 1; i >= 0; i--) { + v = ctx[i]; + val = findInScope(key, v, doModelGet); + if (val !== undefined) { + found = true; + break; + } + } + + if (!found) { + return (returnFound) ? false : ""; + } + + if (!returnFound && typeof val == 'function') { + val = this.mv(val, ctx, partials); + } + + return val; + }, + + // higher order templates + ls: function(func, cx, partials, text, tags) { + var oldTags = this.options.delimiters; + + this.options.delimiters = tags; + this.b(this.ct(coerceToString(func.call(cx, text)), cx, partials)); + this.options.delimiters = oldTags; + + return false; + }, + + // compile text + ct: function(text, cx, partials) { + if (this.options.disableLambda) { + throw new Error('Lambda features disabled.'); + } + return this.c.compile(text, this.options).render(cx, partials); + }, + + // template result buffering + b: function(s) { this.buf += s; }, + + fl: function() { var r = this.buf; this.buf = ''; return r; }, + + // method replace section + ms: function(func, ctx, partials, inverted, start, end, tags) { + var textSource, + cx = ctx[ctx.length - 1], + result = func.call(cx); + + if (typeof result == 'function') { + if (inverted) { + return true; + } else { + textSource = (this.activeSub && this.subsText && this.subsText[this.activeSub]) ? this.subsText[this.activeSub] : this.text; + return this.ls(result, cx, partials, textSource.substring(start, end), tags); + } + } + + return result; + }, + + // method replace variable + mv: function(func, ctx, partials) { + var cx = ctx[ctx.length - 1]; + var result = func.call(cx); + + if (typeof result == 'function') { + return this.ct(coerceToString(result.call(cx)), cx, partials); + } + + return result; + }, + + sub: function(name, context, partials, indent) { + var f = this.subs[name]; + if (f) { + this.activeSub = name; + f(context, partials, this, indent); + this.activeSub = false; + } + } + + }; + + //Find a key in an object + function findInScope(key, scope, doModelGet) { + var val; + + if (scope && typeof scope == 'object') { + + if (scope[key] !== undefined) { + val = scope[key]; + + // try lookup with get for backbone or similar model data + } else if (doModelGet && scope.get && typeof scope.get == 'function') { + val = scope.get(key); + } + } + + return val; + } + + function createSpecializedPartial(instance, subs, partials, stackSubs, stackPartials, stackText) { + function PartialTemplate() {}; + PartialTemplate.prototype = instance; + function Substitutions() {}; + Substitutions.prototype = instance.subs; + var key; + var partial = new PartialTemplate(); + partial.subs = new Substitutions(); + partial.subsText = {}; //hehe. substext. + partial.buf = ''; + + stackSubs = stackSubs || {}; + partial.stackSubs = stackSubs; + partial.subsText = stackText; + for (key in subs) { + if (!stackSubs[key]) stackSubs[key] = subs[key]; + } + for (key in stackSubs) { + partial.subs[key] = stackSubs[key]; + } + + stackPartials = stackPartials || {}; + partial.stackPartials = stackPartials; + for (key in partials) { + if (!stackPartials[key]) stackPartials[key] = partials[key]; + } + for (key in stackPartials) { + partial.partials[key] = stackPartials[key]; + } + + return partial; + } + + var rAmp = /&/g, + rLt = /</g, + rGt = />/g, + rApos = /\'/g, + rQuot = /\"/g, + hChars = /[&<>\"\']/; + + function coerceToString(val) { + return String((val === null || val === undefined) ? '' : val); + } + + function hoganEscape(str) { + str = coerceToString(str); + return hChars.test(str) ? + str + .replace(rAmp, '&') + .replace(rLt, '<') + .replace(rGt, '>') + .replace(rApos, ''') + .replace(rQuot, '"') : + str; + } + + var isArray = Array.isArray || function(a) { + return Object.prototype.toString.call(a) === '[object Array]'; + }; + + })( true ? exports : Hogan); + + +/***/ }, +/* 8 */ /***/ function(module, exports) { var util; diff --git a/resources/mobile.issues/CleanupOverlay.js b/resources/mobile.issues/CleanupOverlay.js index ec6d502..086e88e 100644 --- a/resources/mobile.issues/CleanupOverlay.js +++ b/resources/mobile.issues/CleanupOverlay.js @@ -1,6 +1,6 @@ ( function ( M, $ ) { var Overlay = M.require( 'mobile.overlays/Overlay' ), - Icon = M.require( 'mobile.startup/Icon' ), + Icon = mw.mf.Icon, icon = new Icon( { name: 'cleanup-gray', additionalClassNames: 'issue-notice', diff --git a/resources/mobile.mediaViewer/ImageOverlay.js b/resources/mobile.mediaViewer/ImageOverlay.js index 1896763..024243b 100644 --- a/resources/mobile.mediaViewer/ImageOverlay.js +++ b/resources/mobile.mediaViewer/ImageOverlay.js @@ -1,6 +1,6 @@ ( function ( M, $ ) { var Overlay = M.require( 'mobile.overlays/Overlay' ), - Icon = M.require( 'mobile.startup/Icon' ), + Icon = mw.mf.Icon, Button = M.require( 'mobile.startup/Button' ), ImageGateway = M.require( 'mobile.mediaViewer/ImageGateway' ); diff --git a/resources/mobile.overlays/Overlay.js b/resources/mobile.overlays/Overlay.js index 2547357..784fe86 100644 --- a/resources/mobile.overlays/Overlay.js +++ b/resources/mobile.overlays/Overlay.js @@ -1,7 +1,7 @@ ( function ( M, $ ) { var View = mw.mf.View, - Icon = M.require( 'mobile.startup/Icon' ), + Icon = mw.mf.Icon, Button = M.require( 'mobile.startup/Button' ), Anchor = M.require( 'mobile.startup/Anchor' ), icons = M.require( 'mobile.startup/icons' ), diff --git a/resources/mobile.patrol.ajax/init.js b/resources/mobile.patrol.ajax/init.js index 60575a9..50cab3d 100644 --- a/resources/mobile.patrol.ajax/init.js +++ b/resources/mobile.patrol.ajax/init.js @@ -12,7 +12,7 @@ } $( function () { var $patrolLinks = $( '.patrollink a' ), - Icon = M.require( 'mobile.startup/Icon' ), + Icon = mw.mf.Icon, toast = M.require( 'mobile.toast/toast' ), $spinner = $( new Icon( { name: 'spinner', diff --git a/resources/mobile.references/ReferencesDrawer.js b/resources/mobile.references/ReferencesDrawer.js index 3d16006..9382c83 100644 --- a/resources/mobile.references/ReferencesDrawer.js +++ b/resources/mobile.references/ReferencesDrawer.js @@ -1,7 +1,7 @@ ( function ( M, $ ) { var Drawer = M.require( 'mobile.drawers/Drawer' ), icons = M.require( 'mobile.startup/icons' ), - Icon = M.require( 'mobile.startup/Icon' ); + Icon = mw.mf.Icon; /** * Drawer for references diff --git a/resources/mobile.search/SearchOverlay.js b/resources/mobile.search/SearchOverlay.js index 7cdb52d..6cedfa5 100644 --- a/resources/mobile.search/SearchOverlay.js +++ b/resources/mobile.search/SearchOverlay.js @@ -3,7 +3,7 @@ var Overlay = M.require( 'mobile.overlays/Overlay' ), Anchor = M.require( 'mobile.startup/Anchor' ), - Icon = M.require( 'mobile.startup/Icon' ), + Icon = mw.mf.Icon, WatchstarPageList = M.require( 'mobile.pagelist.scripts/WatchstarPageList' ), SEARCH_DELAY = 300, $html = $( 'html' ), diff --git a/resources/mobile.special.nearby.scripts/nearby.js b/resources/mobile.special.nearby.scripts/nearby.js index 10dbaca..c3a5e61 100644 --- a/resources/mobile.special.nearby.scripts/nearby.js +++ b/resources/mobile.special.nearby.scripts/nearby.js @@ -1,5 +1,5 @@ ( function ( M, $ ) { - var Icon = M.require( 'mobile.startup/Icon' ), + var Icon = mw.mf.Icon, endpoint = mw.config.get( 'wgMFNearbyEndpoint' ), router = require( 'mediawiki.router' ), Nearby = M.require( 'mobile.nearby/Nearby' ); diff --git a/resources/mobile.startup/icons.js b/resources/mobile.startup/icons.js index 7e4d70c..3ee54b9 100644 --- a/resources/mobile.startup/icons.js +++ b/resources/mobile.startup/icons.js @@ -1,6 +1,6 @@ ( function ( M, $ ) { - var Icon = M.require( 'mobile.startup/Icon' ); + var Icon = mw.mf.Icon; /** * A set of shared icons. diff --git a/resources/mobile.talk.overlays/TalkSectionAddOverlay.js b/resources/mobile.talk.overlays/TalkSectionAddOverlay.js index b45e626..70cc987 100644 --- a/resources/mobile.talk.overlays/TalkSectionAddOverlay.js +++ b/resources/mobile.talk.overlays/TalkSectionAddOverlay.js @@ -1,7 +1,7 @@ ( function ( M, $ ) { var TalkOverlayBase = M.require( 'mobile.talk.overlays/TalkOverlayBase' ), toast = M.require( 'mobile.toast/toast' ), - Icon = M.require( 'mobile.startup/Icon' ); + Icon = mw.mf.Icon; /** * Overlay for adding a talk section diff --git a/resources/mobile.toc/TableOfContents.js b/resources/mobile.toc/TableOfContents.js index 0c3754b..92f2350 100644 --- a/resources/mobile.toc/TableOfContents.js +++ b/resources/mobile.toc/TableOfContents.js @@ -1,6 +1,6 @@ ( function ( M ) { var View = mw.mf.View, - Icon = M.require( 'mobile.startup/Icon' ); + Icon = mw.mf.Icon; /** * View for table of contents diff --git a/resources/mobile.toggle/toggle.js b/resources/mobile.toggle/toggle.js index 3ed92da..a756d2b 100644 --- a/resources/mobile.toggle/toggle.js +++ b/resources/mobile.toggle/toggle.js @@ -7,7 +7,7 @@ name: 'arrow', additionalClassNames: 'indicator' }, - Icon = M.require( 'mobile.startup/Icon' ); + Icon = mw.mf.Icon; /** * A class for enabling toggling diff --git a/resources/mobile.watchstar/Watchstar.js b/resources/mobile.watchstar/Watchstar.js index aa1db07..ec698c1 100644 --- a/resources/mobile.watchstar/Watchstar.js +++ b/resources/mobile.watchstar/Watchstar.js @@ -2,7 +2,7 @@ var View = mw.mf.View, WatchstarGateway = M.require( 'mobile.watchstar/WatchstarGateway' ), - Icon = M.require( 'mobile.startup/Icon' ), + Icon = mw.mf.Icon, watchIcon = new Icon( { name: 'watch', additionalClassNames: 'watch-this-article' diff --git a/resources/skins.minerva.editor/init.js b/resources/skins.minerva.editor/init.js index 046acb9..f3e5242 100644 --- a/resources/skins.minerva.editor/init.js +++ b/resources/skins.minerva.editor/init.js @@ -8,7 +8,7 @@ router = require( 'mediawiki.router' ), overlayManager = M.require( 'skins.minerva.scripts/overlayManager' ), loader = M.require( 'mobile.overlays/moduleLoader' ), - Icon = M.require( 'mobile.startup/Icon' ), + Icon = mw.mf.Icon, Button = M.require( 'mobile.startup/Button' ), Anchor = M.require( 'mobile.startup/Anchor' ), skin = M.require( 'skins.minerva.scripts/skin' ), diff --git a/tests/qunit/mobile.pagelist.scripts/test_WatchstarPageList.js b/tests/qunit/mobile.pagelist.scripts/test_WatchstarPageList.js index a04eb25..a45e27f 100644 --- a/tests/qunit/mobile.pagelist.scripts/test_WatchstarPageList.js +++ b/tests/qunit/mobile.pagelist.scripts/test_WatchstarPageList.js @@ -2,7 +2,7 @@ var PageList = M.require( 'mobile.pagelist.scripts/WatchstarPageList' ), user = M.require( 'mobile.user/user' ), - Icon = M.require( 'mobile.startup/Icon' ), + Icon = mw.mf.Icon, watchIcon = new Icon( { name: 'watched' } ); diff --git a/tests/qunit/mobile.watchlist/test_WatchList.js b/tests/qunit/mobile.watchlist/test_WatchList.js index 7c2d7ae..a1da53a 100644 --- a/tests/qunit/mobile.watchlist/test_WatchList.js +++ b/tests/qunit/mobile.watchlist/test_WatchList.js @@ -2,7 +2,7 @@ var WatchList = M.require( 'mobile.watchlist/WatchList' ), user = M.require( 'mobile.user/user' ), - Icon = M.require( 'mobile.startup/Icon' ), + Icon = mw.mf.Icon, watchIcon = new Icon( { name: 'watched' } ); diff --git a/tests/qunit/mobile.watchstar/test_Watchstar.js b/tests/qunit/mobile.watchstar/test_Watchstar.js index 76e6f9a..5004d8b 100644 --- a/tests/qunit/mobile.watchstar/test_Watchstar.js +++ b/tests/qunit/mobile.watchstar/test_Watchstar.js @@ -3,7 +3,7 @@ var Watchstar = M.require( 'mobile.watchstar/Watchstar' ), CtaDrawer = M.require( 'mobile.drawers/CtaDrawer' ), toast = M.require( 'mobile.toast/toast' ), - Icon = M.require( 'mobile.startup/Icon' ), + Icon = mw.mf.Icon, watchIcon = new Icon( { name: 'watched' } ), diff --git a/webpack.config.js b/webpack.config.js index 5b855f3..9164ed6 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -10,6 +10,14 @@ // the "index" entry gets written to index.js. filename: '/[name]/index.js' }, + module: { + loaders: [ + { + test: /\.hogan/, + loader: 'mustache?noShortcut' + } + ] + }, entry: { 'mobile.frontend': './build_resources/mobile.frontend/index.js' } -- To view, visit https://gerrit.wikimedia.org/r/332926 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If9dca17ecfecc385928ba326e39134cfbdb32f72 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/MobileFrontend Gerrit-Branch: mfui Gerrit-Owner: Jdlrobson <jrob...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits