diff --git a/controllers/script.js b/controllers/script.js index 614957fa0..f6ae00f78 100644 --- a/controllers/script.js +++ b/controllers/script.js @@ -50,10 +50,11 @@ var getScriptPageTasks = function (aOptions) { var authedUser = aOptions.authedUser; // Intermediates - var homepagesURL = null; - var copyrights = null; - var licenses = null; - var collaborators = null; + var homepageURL = null; + var copyright = null; + var license = null; + var author = null; + var collaborator = null; // Temporaries var htmlStub = null; @@ -93,79 +94,55 @@ var getScriptPageTasks = function (aOptions) { }); // Show homepages of the script - homepagesURL = scriptStorage.findMeta(script.meta, 'homepageURL'); - if (homepagesURL) { - if (typeof homepagesURL === 'string') { - htmlStub = ''; + homepageURL = scriptStorage.findMeta(script.meta, 'UserScript.homepageURL'); + if (homepageURL) { + aOptions.script.homepages = []; + homepageURL.forEach(function (aElement, aIndex, aArray) { + htmlStub = ''; if (htmlStub === sanitizeHtml(htmlStub, htmlWhitelistLink)) { - aOptions.script.homepages = [{ - url: homepagesURL, - text: decodeURI(homepagesURL), + aOptions.script.homepages.unshift({ + url: aElement.value, + text: decodeURI(aElement.value), hasNoFollow: !/^(?:https?:\/\/)?openuserjs\.org\//i. - test(homepagesURL) - }]; + test(aElement.value) + }); } - } else { - aOptions.script.homepages = []; - homepagesURL.forEach(function (aHomepage) { - htmlStub = ''; - if (htmlStub === sanitizeHtml(htmlStub, htmlWhitelistLink)) { - aOptions.script.homepages.unshift({ - url: aHomepage, - text: decodeURI(aHomepage), - hasNoFollow: !/^(?:https?:\/\/)?openuserjs\.org/i.test(aHomepage) - }); - } - }); - } + }); } // Show copyrights of the script - copyrights = scriptStorage.findMeta(script.meta, 'copyright'); - if (copyrights) { - if (typeof copyrights === 'string') { - aOptions.script.copyrights = [{ name: copyrights }]; - } else { - aOptions.script.copyrights = []; - copyrights.forEach(function (aCopyright) { - aOptions.script.copyrights.unshift({ name: aCopyright }); - }); - } + copyright = scriptStorage.findMeta(script.meta, 'UserScript.copyright'); + if (copyright) { + aOptions.script.copyrights = []; + copyright.forEach(function (aElement, aIndex, aArray) { + aOptions.script.copyrights.unshift({ name: aElement.value }); + }); } // Show licensings of the script - licenses = scriptStorage.findMeta(script.meta, 'license'); - if (licenses) { - if (typeof licenses === 'string') { - aOptions.script.licenses = [{ name: licenses }]; - } else { - aOptions.script.licenses = []; - licenses.forEach(function (aLicense) { - aOptions.script.licenses.unshift({ name: aLicense }); - }); - } + license = scriptStorage.findMeta(script.meta, 'UserScript.license'); + if (license) { + aOptions.script.licenses = []; + license.forEach(function (aElement, aIndex, aArray) { + aOptions.script.licenses.unshift({ name: aElement.value }); + }); } else if (!script.isLib) { aOptions.script.licenses = [{ name: 'MIT License (Expat)' }]; } // Show collaborators of the script - - collaborators = scriptStorage.findMeta(script.meta, 'oujs.collaborator'); - if (scriptStorage.findMeta(script.meta, 'oujs.author') && collaborators) { - + author = scriptStorage.findMeta(script.meta, 'OpenUserJS.author.0.value'); + collaborator = scriptStorage.findMeta(script.meta, 'OpenUserJS.collaborator'); + if (author && collaborator) { aOptions.hasCollab = true; - if (typeof collaborators === 'string') { - aOptions.script.collaborators = [{ - url: encodeURIComponent(collaborators), - text: collaborators }]; - } else { - aOptions.script.collaborators = []; - collaborators.forEach(function (aCollaborator) { - aOptions.script.collaborators.unshift({ - url: encodeURIComponent(aCollaborator), - text: aCollaborator }); + + aOptions.script.collaborators = []; + collaborator.forEach(function (aElement, aIndex, aArray) { + aOptions.script.collaborators.unshift({ + url: encodeURIComponent(aElement.value), + text: aElement.value }); - } + }); } // Show which libraries hosted on the site a script uses @@ -339,7 +316,7 @@ exports.view = function (aReq, aRes, aNext) { function preRender() { if (script.groups) { pageMetadata(options, ['About', script.name, (script.isLib ? 'Libraries' : 'Scripts')], - scriptStorage.findMeta(script.meta, 'description'), _.pluck(script.groups, 'name')); + script.description, _.pluck(script.groups, 'name')); } } function render() { aRes.render('pages/scriptPage', options); } @@ -368,7 +345,7 @@ exports.view = function (aReq, aRes, aNext) { // Page metadata pageMetadata(options, ['About', script.name, (script.isLib ? 'Libraries' : 'Scripts')], - scriptStorage.findMeta(script.meta, 'description')); + script.description); options.isScriptPage = true; // SearchBar diff --git a/controllers/scriptStorage.js b/controllers/scriptStorage.js index 437d0240e..16a730463 100644 --- a/controllers/scriptStorage.js +++ b/controllers/scriptStorage.js @@ -6,6 +6,8 @@ var isDev = require('../libs/debug').isDev; var isDbg = require('../libs/debug').isDbg; // +var fs = require('fs'); +var PEG = require('pegjs'); var AWS = require('aws-sdk'); var Script = require('../models/script').Script; @@ -16,6 +18,16 @@ var cleanFilename = require('../libs/helpers').cleanFilename; var findDeadorAlive = require('../libs/remove').findDeadorAlive; var userRoles = require('../models/userRoles.json'); +var parsers = (function () { + return { + UserScript: PEG.buildParser(fs.readFileSync('./public/pegjs/blockUserScript.pegjs', 'utf8'), + { allowedStartRules: ['line'] }), + OpenUserJS: PEG.buildParser(fs.readFileSync('./public/pegjs/blockOpenUserJS.pegjs', 'utf8'), + { allowedStartRules: ['line'] }) + }; +})(); +exports.parsers = parsers; + var bucketName = 'OpenUserJS.org'; var DEV_AWS_URL = null; @@ -176,9 +188,6 @@ exports.sendMeta = function (aReq, aRes, aNext) { Script.findOne({ installName: caseSensitive(installName) }, function (aErr, aScript) { var meta = null; - var data = null; - var prefix = null; - var key = null; var whitespace = '\u0020\u0020\u0020\u0020'; if (!aScript) { @@ -192,33 +201,26 @@ exports.sendMeta = function (aReq, aRes, aNext) { meta = aScript.meta; // NOTE: Watchpoint - aRes.write('// ==UserScript==\n'); - Object.keys(meta).reverse().forEach(function (aName) { - if (meta[aName] instanceof Array) { - meta[aName].forEach(function (aValue) { - aRes.write('// @' + aName + (aValue ? whitespace + aValue : '') + '\n'); + Object.keys(meta).reverse().forEach(function (aBlock) { + aRes.write('// ==' + aBlock + '==\n'); + + Object.keys(meta[aBlock]).reverse().forEach(function (aKey) { + Object.keys(meta[aBlock][aKey]).forEach(function (aIndex) { + var header = meta[aBlock][aKey][aIndex]; + var key = null; + var value = null; + + key = (header ? header.key : null) || aKey; + value = (header ? header.value : null); + + aRes.write('// @' + key + (value ? whitespace + value : '') + '\n'); }); - } else if (meta[aName] instanceof Object) { - prefix = aName; - for (key in meta[aName]) { - data = meta[prefix][key]; - if (data instanceof Array) { - data.forEach(function (aValue) { - aRes.write('// @' + prefix + ':' + key + (aValue ? whitespace + aValue : '') + - '\n'); - }); - } - else { - aRes.write('// @' + prefix + ':' + key + (data ? whitespace + data : '') + '\n'); - } - } - } else { - data = meta[aName]; - aRes.write('// @' + aName + (data ? whitespace + data : '') + '\n'); - } + }); + + aRes.write('// ==/' + aBlock + '==\n\n'); }); - aRes.end('// ==/UserScript==\n'); - }); + aRes.end(); + }); }; function findMeta(aMeta, aQuery) { @@ -247,126 +249,115 @@ function findMeta(aMeta, aQuery) { } exports.findMeta = findMeta; -// Modified from Count Issues (http://userscripts.org/scripts/show/69307) -// By Marti Martz (http://userscripts.org/users/37004) -function parseMeta(aString, aNormalize) { +// Parse a specific metadata block content with a specified *pegjs* parser +function parseMeta(aParser, aString) { var lines = {}; var rLine = /\/\/ @(\S+)(?:\s+(.*))?/; var line = null; var header = null; - - var headers = {}; - var lineMatches = null; - var name = null; - var value = null; var key = null; - var prefix = null; + var keyword = null; + var name = null; var unique = null; - var one = null; - var uniques = { - 'description': true, - 'icon': true, - 'icon64': true, - 'name': true, - 'namespace': true, - 'version': true, - 'oujs:author': true - }; - var matches = null; - + var headers = {}; + var i = null; + var thisHeader = null; lines = aString.split(/[\r\n]+/).filter(function (aElement, aIndex, aArray) { return (aElement.match(rLine)); }); for (line in lines) { - header = null; - - lineMatches = lines[line].replace(/\s+$/, '').match(rLine); - name = lineMatches[1]; - value = lineMatches[2]; - if (aNormalize) { - // Upmix from... - switch (name) { - case 'homepage': - case 'source': - case 'website': - name = 'homepageURL'; - break; - case 'defaulticon': - case 'iconURL': - name = 'icon'; - break; - case 'licence': - name = 'license'; - break; - } + try { + header = aParser.parse(lines[line], { startRule: 'line' }); + } catch (aE) { + // Ignore anything not understood + header = null; } - name = name.split(/:/).reverse(); - key = name[0]; - prefix = name[1]; - if (key) { - unique = {}; - if (prefix) { - if (!headers[prefix]) { - headers[prefix] = {}; - } - header = headers[prefix]; - if (aNormalize) { - for (one in uniques) { - matches = one.match(/(.*):(.*)$/); - if (uniques[one] && matches && matches[1] === prefix) { - unique[matches[2]] = true; - } + + if (header) { + key = header.key; + keyword = header.keyword; + name = keyword || key; + unique = header.unique; + + delete header.unique; + + // Create if doesn't exist + if (!headers[name]) { + headers[name] = []; + } + + // Check for unique + if (unique) { + for (i = 0; thisHeader = headers[name][i]; ++i) { + if (thisHeader.key === header.key) { + headers[name].splice(i, 1); } } } else { - header = headers; - if (aNormalize) { - for (one in uniques) { - if (uniques[one] && !/:/.test(one)) { - unique[one] = true; - } + for (i = 0; thisHeader = headers[name][i]; ++i) { + if (thisHeader.value === header.value) { + headers[name].splice(i, 1); } } } - if (!header[key] || aNormalize && unique[key]) { - try { - header[key] = value || ''; - } catch (aE) { - // Ignore this key on read only exception fault and log... See #285 commit history - console.log('WARNING: Key name `@' + lineMatches[1] + '` failed in parseMeta'); - } - } else if (!aNormalize || header[key] !== (value || '') - && !(header[key] instanceof Array && header[key].indexOf(value) > -1)) { - if (!(header[key] instanceof Array)) { - header[key] = [header[key]]; - } - header[key].push(value || ''); - } + + headers[name].push(header); } } + // Clean up for DB storage + for (name in headers) { + headers[name].forEach(function (aElement, aIndex, aArray) { + if (!aElement.keyword) { + delete aElement.key; + } + }); + } + return headers; } exports.parseMeta = parseMeta; exports.getMeta = function (aChunks, aCallback) { // We need to convert the array of buffers to a string to - // parse the header. But strings are memory inefficient compared + // parse the blocks. But strings are memory inefficient compared // to buffers so we only convert the least number of chunks to - // get the user script header. + // get the metadata blocks. var i = 0; - var header = null; var str = ''; + var parser = null; + var rHeaderContent = null; + var headerContent = null; + var hasUserScriptHeaderContent = false; + var blocksContent = {}; + var blocks = {}; for (; i < aChunks.length; ++i) { - header = null; str += aChunks[i]; - header = /^(?:\uFEFF)?\/\/ ==UserScript==([\s\S]*?)^\/\/ ==\/UserScript==/m.exec(str); - if (header && header[1]) { - return aCallback(parseMeta(header[1], true)); + for (parser in parsers) { + rHeaderContent = new RegExp( + '^(?:\\uFEFF)?\/\/ ==' + parser + '==([\\s\\S]*?)^\/\/ ==\/'+ parser + '==', 'm' + ); + headerContent = rHeaderContent.exec(str); + if (headerContent && headerContent[1]) { + if (parser === 'UserScript') { + hasUserScriptHeaderContent = true; + } + + blocksContent[parser] = headerContent[1]; + } + } + + if (hasUserScriptHeaderContent) { + for (parser in parsers) { + if (blocksContent[parser]) { + blocks[parser] = parseMeta(parsers[parser], blocksContent[parser]); + } + } + return aCallback(blocks); } } @@ -376,6 +367,7 @@ exports.getMeta = function (aChunks, aCallback) { exports.storeScript = function (aUser, aMeta, aBuf, aCallback, aUpdate) { var isLibrary = typeof aMeta === 'string'; var name = null; + var thisName = null; var scriptName = null; var author = null; var collaborators = null; @@ -395,34 +387,39 @@ exports.storeScript = function (aUser, aMeta, aBuf, aCallback, aUpdate) { } if (!isLibrary) { - name = findMeta(aMeta, 'name'); - scriptName = typeof name === 'string' ? cleanFilename(name, '') : null; + name = findMeta(aMeta, 'UserScript.name'); // Can't install a script without a @name (maybe replace with random value) + if (!name) { + return aCallback(null); + } + + name.forEach(function (aElement, aIndex, aArray) { + if (!name[aIndex].key) { + thisName = aElement.value; + scriptName = cleanFilename(thisName, ''); + } + }); + + // Can't install a script without a cleaned @name (maybe replace with random value) if (!scriptName) { return aCallback(null); } - author = findMeta(aMeta, 'oujs.author'); - collaborators = findMeta(aMeta, 'oujs.collaborator'); + author = findMeta(aMeta, 'OpenUserJS.author.0.value'); + collaborators = findMeta(aMeta, 'OpenUserJS.collaborator.value'); - if (!isLibrary && author !== aUser.name && collaborators) { - if ((typeof collaborators === 'string' && collaborators === aUser.name) || - (collaborators instanceof Array && collaborators.indexOf(aUser.name) > -1)) { + if (!isLibrary && author !== aUser.name && + collaborators && collaborators.indexOf(aUser.name) > -1) { - installName = author + '/'; - collaboration = true; - } + installName = author + '/'; + collaboration = true; } installName += scriptName + '.user.js'; - requires = findMeta(aMeta, 'require'); + requires = findMeta(aMeta, 'UserScript.require.value'); if (requires) { - if (typeof requires === 'string') { - requires = [requires]; - } - requires.forEach(function (aRequire) { match = rLibrary.exec(aRequire); if (match) { @@ -455,7 +452,7 @@ exports.storeScript = function (aUser, aMeta, aBuf, aCallback, aUpdate) { } else if (!aScript) { // New script aScript = new Script({ - name: isLibrary ? aMeta : findMeta(aMeta, 'name'), + name: isLibrary ? aMeta : thisName, author: aUser.name, installs: 0, rating: 0, @@ -480,16 +477,20 @@ exports.storeScript = function (aUser, aMeta, aBuf, aCallback, aUpdate) { // Script already exists. if (!aScript.isLib) { if (collaboration && - (findMeta(script.meta, 'oujs.author') !== findMeta(aMeta, 'oujs.author') || - JSON.stringify(findMeta(script.meta, 'oujs.collaborator')) != - JSON.stringify(collaborators))) { + (findMeta(script.meta, 'OpenUserJS.author.0.value') !== + findMeta(aMeta, 'OpenUserJS.author.0.value') || + JSON.stringify(findMeta(script.meta, 'OpenUserJS.collaborator.value')) !== + JSON.stringify(collaborators))) { + return aCallback(null); } aScript.meta = aMeta; aScript.uses = libraries; } aScript.updated = new Date(); - if (findMeta(script.meta, 'version') !== findMeta(aMeta, 'version')) { + if (findMeta(script.meta, 'UserScript.version.0.value') !== + findMeta(aMeta, 'UserScript.version.0.value')) { + aScript.installsSinceUpdate = 0; } } diff --git a/controllers/user.js b/controllers/user.js index 82ad7d2d0..68196e100 100644 --- a/controllers/user.js +++ b/controllers/user.js @@ -869,11 +869,19 @@ exports.userGitHubImportScriptPage = function (aReq, aRes, aNext) { }, aCallback); }, function (aBlobUtf8, aCallback) { + var onScriptStored = null; + var parser = null; + var rHeaderContent = null; + var headerContent = null; + var hasUserScriptHeaderContent = false; + var blocksContent = {}; + var blocks = {}; + // Double check file size. if (aBlobUtf8.length > settings.maximum_upload_script_size) return aCallback(util.format('File size is larger than maximum (%s bytes).', settings.maximum_upload_script_size)); - var onScriptStored = function (aScript) { + onScriptStored = function (aScript) { if (aScript) { options.script = aScript; aCallback(null); @@ -883,12 +891,29 @@ exports.userGitHubImportScriptPage = function (aReq, aRes, aNext) { }; if (options.javascriptBlob.isUserJS) { - // - var userscriptHeaderRegex = /^(?:\uFEFF)?\/\/ ==UserScript==([\s\S]*?)^\/\/ ==\/UserScript==/m; - var m = userscriptHeaderRegex.exec(aBlobUtf8); - if (m && m[1]) { - var userscriptMeta = scriptStorage.parseMeta(m[1], true); - scriptStorage.storeScript(authedUser, userscriptMeta, aBlobUtf8, onScriptStored); + for (parser in scriptStorage.parsers) { + rHeaderContent = new RegExp( + '^(?:\\uFEFF)?\/\/ ==' + parser + '==([\\s\\S]*?)^\/\/ ==\/'+ parser + '==', 'm' + ); + headerContent = rHeaderContent.exec(aBlobUtf8); + if (headerContent && headerContent[1]) { + if (parser === 'UserScript') { + hasUserScriptHeaderContent = true; + } + + blocksContent[parser] = headerContent[1]; + } + } + + if (hasUserScriptHeaderContent) { + for (parser in scriptStorage.parsers) { + if (blocksContent[parser]) { + blocks[parser] = scriptStorage.parseMeta( + scriptStorage.parsers[parser], blocksContent[parser] + ); + } + } + scriptStorage.storeScript(authedUser, blocks, aBlobUtf8, onScriptStored); } else { aCallback('Specified file does not contain a userscript header.'); } @@ -1170,9 +1195,25 @@ exports.submitSource = function (aReq, aRes, aNext) { storeScript(aReq.body.script_name, source); } else { scriptStorage.getMeta([source], function (aMeta) { - if (!scriptStorage.findMeta(aMeta, 'name')) { + var name = null; + var hasName = false; + + name = scriptStorage.findMeta(aMeta, 'UserScript.name'); + + if (!name) { + return aRes.redirect(url); + } + + name.forEach(function (aElement, aIndex, aArray) { + if (!name[aIndex].key) { + hasName = true; + } + }); + + if (!hasName) { return aRes.redirect(url); } + storeScript(aMeta, source); }); } @@ -1182,7 +1223,6 @@ function getExistingScript(aReq, aOptions, aAuthedUser, aCallback) { aOptions.isLib = aReq.params.isLib; if (aReq.params.isNew) { - // A user who isn't logged in can't write a new script if (!aAuthedUser) { return aCallback(null); @@ -1208,12 +1248,8 @@ function getExistingScript(aReq, aOptions, aAuthedUser, aCallback) { return aCallback(null); } - collaborators = scriptStorage.findMeta(aScript.meta, 'oujs.collaborator'); - if (collaborators) { - if (typeof collaborators === 'string') { - collaborators = [collaborators]; - } - } else { + collaborators = scriptStorage.findMeta(aScript.meta, 'OpenUserJS.collaborator.value'); + if (!collaborators) { collaborators = []; // NOTE: Watchpoint } @@ -1239,7 +1275,6 @@ function getExistingScript(aReq, aOptions, aAuthedUser, aCallback) { } exports.editScript = function (aReq, aRes, aNext) { - var authedUser = aReq.session.user; var isNew = aReq.params.isNew; @@ -1313,7 +1348,9 @@ exports.editScript = function (aReq, aRes, aNext) { } else { //--- async.parallel(tasks, function (aErr) { - if (aErr) return aNext(); + if (aErr) { + return aNext(); + } aRes.render('pages/scriptViewSourcePage', options); }); diff --git a/libs/modelParser.js b/libs/modelParser.js index d58ed3e9f..94c4d9a9b 100644 --- a/libs/modelParser.js +++ b/libs/modelParser.js @@ -116,6 +116,7 @@ var parseScript = function (aScriptData) { var script = aScriptData.toObject ? aScriptData.toObject({ virtuals: true }) : aScriptData; // Intermediates + var description = null; var icon = null; var supportURL = null; @@ -127,47 +128,41 @@ var parseScript = function (aScriptData) { script.author = parseUser({ name: script.author }); } + // Description default + description = findMeta(script.meta, 'UserScript.description'); + if (description) { + description.forEach(function (aElement, aIndex, aArray) { + if (!description[aIndex].key) { + script.description = aElement.value; + } + }); + } + // Icons - icon = findMeta(script.meta, 'icon'); + icon = findMeta(script.meta, 'UserScript.icon.0.value'); if (icon) { - // TODO: `@icon` has been unique but may not be in early scripts in the DB. - // Should be fixed on migration so this can be modified - if (_.isString(icon)) { - script.icon16Url = icon; - script.icon45Url = icon; - } else if (_.isArray(icon) && !_.isEmpty(icon)) { // NOTE: Should never be empty - script.icon16Url = icon[icon.length - 1]; - script.icon45Url = icon[icon.length - 1]; - } + script.icon16Url = icon; + script.icon45Url = icon; } - icon = findMeta(script.meta, 'icon64'); + icon = findMeta(script.meta, 'UserScript.icon64.0.value'); if (icon) { + // Local downmix script.icon45Url = icon; } // Support Url - supportURL = findMeta(script.meta, 'supportURL'); + supportURL = findMeta(script.meta, 'UserScript.supportURL.0.value'); if (supportURL) { - script.hasSupport = true; - if (_.isString(supportURL)) { - htmlStub = ''; - if (htmlStub === sanitizeHtml(htmlStub, htmlWhitelistLink)) { - script.support = [{ - url: supportURL, - text: decodeURI(supportURL), - hasNoFollow: !/^(?:https?:\/\/)?openuserjs\.org/i.test(supportURL) - }]; - } - } else if (_.isArray(supportURL) && !_.isEmpty(supportURL)) { // NOTE: Should never be empty - htmlStub = ''; - if (htmlStub === sanitizeHtml(htmlStub, htmlWhitelistLink)) { - script.support = [{ - url: supportURL[supportURL.length - 1], - text: decodeURI(supportURL[supportURL.length - 1]), - hasNoFollow: !/^(?:https?:\/\/)?openuserjs\.org/i.test(supportURL[supportURL.length - 1]) - }]; - } + htmlStub = ''; + if (htmlStub === sanitizeHtml(htmlStub, htmlWhitelistLink)) { + script.hasSupport = true; + + script.support = [{ + url: supportURL, + text: decodeURI(supportURL), + hasNoFollow: !/^(?:https?:\/\/)?openuserjs\.org/i.test(supportURL) + }]; } } diff --git a/libs/modelQuery.js b/libs/modelQuery.js index d603793aa..906a8f84b 100644 --- a/libs/modelQuery.js +++ b/libs/modelQuery.js @@ -113,8 +113,8 @@ var parseModelListSearchQuery = function (aModelListQuery, aQuery, aSearchOption var parseScriptSearchQuery = function (aScriptListQuery, aQuery) { parseModelListSearchQuery(aScriptListQuery, aQuery, { - partialWordMatchFields: ['name', 'author', 'about', 'meta.description'], - fullWordMatchFields: ['meta.include', 'meta.match'] + partialWordMatchFields: ['name', 'author', 'about', 'meta.UserScript.description.value'], + fullWordMatchFields: ['meta.UserScript.include.value', 'meta.UserScript.match.value'] }); }; exports.parseScriptSearchQuery = parseScriptSearchQuery; diff --git a/package.json b/package.json index 2e16dc545..4700d2f79 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "OpenUserJS.org", "description": "An open source user scripts repo built using Node.js", - "version": "0.1.9", + "version": "0.2.0", "main": "app", "dependencies": { "ace-builds": "git://github.com/ajaxorg/ace-builds#0982db4", @@ -50,6 +50,7 @@ "passport-twitter": "1.0.3", "passport-windowslive": "1.0.1", "passport-yahoo": "0.3.0", + "pegjs": "0.8.0", "request": "2.60.0", "sanitize-html": "1.8.0", "select2": "3.5.2-browserify", diff --git a/public/pegjs/blockUserScript.pegjs b/public/pegjs/blockUserScript.pegjs index 182a51e6d..c949e88cb 100644 --- a/public/pegjs/blockUserScript.pegjs +++ b/public/pegjs/blockUserScript.pegjs @@ -110,7 +110,7 @@ item0 = { return { unique: true, - + key: upmix(keyword) }; } @@ -125,6 +125,7 @@ item1 = 'namespace' / 'installURL' / 'iconURL' / + 'icon64' / 'icon' / 'downloadURL' / 'defaulticon' diff --git a/views/includes/scriptList.html b/views/includes/scriptList.html index 4e1024bc7..f5612212c 100644 --- a/views/includes/scriptList.html +++ b/views/includes/scriptList.html @@ -15,11 +15,11 @@ {{#isLib}}{{/isLib}}{{^isLib}}{{/isLib}} {{name}} - {{#meta.version}} - {{meta.version}} - {{/meta.version}} + {{#meta.UserScript.version}} + {{value}} + {{/meta.UserScript.version}} by {{author.name}} -

{{meta.description}}

+ {{#description}}

{{description}}

{{/description}} {{^librariesOnly}} diff --git a/views/pages/newScriptPage.html b/views/pages/newScriptPage.html index 9b591ef44..579b33c01 100644 --- a/views/pages/newScriptPage.html +++ b/views/pages/newScriptPage.html @@ -18,54 +18,53 @@
{{#newUserJS}} -

Script Metadata

+

Script Metadata

-

You may read about most UserScript metadata blocks on the Greasespot wiki and at the Greasemonkey on SourceForge wiki.

+

You may read about most UserScript metadata block keys on the Greasespot wiki and at the Greasemonkey on SourceForge wiki. Some recommended ones are listed below with their respective metadata block names.

-

OpenUserJS.org Supported

+

UserScript Block

+

OpenUserJS Block

+ - - -

Collaboration

-
-
-

To allow other users to upload modified versions of your script to your account, add @oujs:author {{#authedUser}}{{authedUser.name}}{{/authedUser}}{{^authedUser}}username{{/authedUser}} to the metadata of your script, along with @oujs:collaborator username for every user you wish to give write access. Only the real author of the script may modify these metadata keys. Collaborators may not use GitHub integration to update the script. Add them as collaborators to the GitHub repo instead.

+
@collaborator username
+

May be defined multiple times. Required for Collaboration. All values shown in reverse order.

{{/newUserJS}} @@ -74,7 +73,7 @@

Library Docs

OpenUserJS.org Supported

-

Any UserScript on OpenUserJS.org that //@require's libraries from OpenUserJS.org will link to the library on the UserScript page.

+

Any UserScript on OpenUserJS.org that // @require's libraries from OpenUserJS.org will link to the library on the UserScript page.

{{/newJSLibrary}} @@ -118,7 +117,7 @@

Upload Sc

Fork An Existing Script

- While logged in, click the fork button on any script's main page, or view a script's source and "Submit Code as Fork". + While logged in view a script's source and click "Submit Code as Fork".

@@ -149,6 +148,19 @@

Instructions

After adding the webhook, push a change to GitHub to make sure it's working.

+ + {{#newUserJS}} + +

Collaboration

+
+
+

To allow other users to upload modified versions of your script to your account from this site create an OpenUserJS metadata block and add the necessary keys... one for you yourself and for every existing user you wish to give write access as demonstrated here:

// ==OpenUserJS==
// @author {{#authedUser}}{{authedUser.name}}{{/authedUser}}{{^authedUser}}username{{/authedUser}}
// @collaborator username
// ==/OpenUserJS==
Only the real author of the script may modify these metadata keys.

+

Collaborators on this site may not use GitHub integration to update the script. Add them as collaborators to the GitHub repository instead.

+

If the webhook is enabled on the GitHub repository it will clobber any changes here on this site.

+
+
+ {{/newUserJS}} + diff --git a/views/pages/scriptPage.html b/views/pages/scriptPage.html index 3eee79802..c56f5efed 100644 --- a/views/pages/scriptPage.html +++ b/views/pages/scriptPage.html @@ -24,15 +24,15 @@

Published:

- {{#script.meta.version}} -

Version: {{script.meta.version}}{{#script.isUpdated}} updated {{/script.isUpdated}}

- {{/script.meta.version}} - {{^script.meta.version}} + {{#script.meta.UserScript.version}} +

Version: {{value}}{{#script.isUpdated}} updated {{/script.isUpdated}}

+ {{/script.meta.UserScript.version}} + {{^script.meta.UserScript.version}} {{#script.isUpdated}}

Updated:

{{/script.isUpdated}} - {{/script.meta.version}} - {{#script.meta.description}}

Summary: {{script.meta.description}}

{{/script.meta.description}} + {{/script.meta.UserScript.version}} + {{#script.description}}

Summary: {{script.description}}

{{/script.description}} {{#script.hasGroups}} Groups: