From c6ea9f1fa7f50239dbdfdf40bd6d3630375f8b0a Mon Sep 17 00:00:00 2001 From: Wiktor Olejniczak Date: Thu, 1 Mar 2018 18:23:11 +0100 Subject: [PATCH 1/5] Added support for Polymer 2 and Hybrid mode --- bower.json | 10 +- polymer-sortablejs-template.html | 163 +++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 polymer-sortablejs-template.html diff --git a/bower.json b/bower.json index 94be943..a679dfe 100644 --- a/bower.json +++ b/bower.json @@ -25,7 +25,15 @@ "tests" ], "dependencies": { - "polymer": "polymer/polymer#^1.6.0", + "polymer": "polymer/polymer#1.9 - 2", "Sortable": "sortablejs#^1.4.2" + }, + "variants": { + "1.x": { + "dependencies": { + "polymer": "polymer/polymer#1.9", + "Sortable": "sortablejs#^1.4.2" + } + } } } diff --git a/polymer-sortablejs-template.html b/polymer-sortablejs-template.html new file mode 100644 index 0000000..964c486 --- /dev/null +++ b/polymer-sortablejs-template.html @@ -0,0 +1,163 @@ + + + + + + + From d978bf3a6f495230e3a550602f023fa167b7d469 Mon Sep 17 00:00:00 2001 From: Wiktor Olejniczak Date: Thu, 1 Mar 2018 18:24:45 +0100 Subject: [PATCH 2/5] Removed files that shouldn't be skipped and added VSCode folders to ignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 4d50219..9c34e25 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ node_modules bower_components -mock.png .*.sw* .build* jquery.fn.* -/test +.vscode \ No newline at end of file From 72ea4d9f1e070228a113952a116d7ec45876be44 Mon Sep 17 00:00:00 2001 From: Wiktor Olejniczak Date: Thu, 1 Mar 2018 18:33:01 +0100 Subject: [PATCH 3/5] Updated for latest Bower release available --- bower.json | 4 +- polymer-sortablejs.html | 153 ++++++++++++++++++++++++++-------------- 2 files changed, 102 insertions(+), 55 deletions(-) diff --git a/bower.json b/bower.json index a679dfe..471d5ac 100644 --- a/bower.json +++ b/bower.json @@ -26,13 +26,13 @@ ], "dependencies": { "polymer": "polymer/polymer#1.9 - 2", - "Sortable": "sortablejs#^1.4.2" + "Sortable": "sortablejs#^1.6.0" }, "variants": { "1.x": { "dependencies": { "polymer": "polymer/polymer#1.9", - "Sortable": "sortablejs#^1.4.2" + "Sortable": "sortablejs#^1.6.0" } } } diff --git a/polymer-sortablejs.html b/polymer-sortablejs.html index 215174b..de1e1e4 100644 --- a/polymer-sortablejs.html +++ b/polymer-sortablejs.html @@ -3,7 +3,7 @@ From ec530d96f4412841d60b9d462c4bdc9bb8f3c67c Mon Sep 17 00:00:00 2001 From: Wiktor Olejniczak Date: Thu, 1 Mar 2018 18:55:53 +0100 Subject: [PATCH 4/5] Added automatic build script --- CONTRIBUTING.md | 51 ++++++++++++++ build.js | 176 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 CONTRIBUTING.md create mode 100644 build.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3b9c6cb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,51 @@ +# Contributing + +This element contains a script to automatically rebuild it for choosen Sortable release. + +**TL;DR** + +- Change `polymer-sortablejs-template.html` file instead of ~~`polymer-sortablejs.html`~~ +- Run `$ node bower_components/polymer-sortablejs/build.js` to update and rebuild element + +## Overview + +When _there's an update to Sortable framework_ for which this element is a wraper or you want to _rebuild to include changes you made in template_, you should run `build.js` script inside of element folder with **Node 8** or newer. It will overwrite `polymer-sortable.html` with content of template file `polymer-sortable-template.html` and all options in currently installed Sortable version, excluding those that are defined at the top of `build.js` file. + +### Choosing SOrtable version + +By default script looks for Sortable files in bower_components and node_modules and will use currently installed verison. +If it can't find them, script will download from GitHub (RubaXa/Sortable#master). You can use `-b` to specify branch or `-u` - username from which Sortable will be downloaded. + +### Exluding options + +On top of `build.js` file there is a constant Array + +````javascript +const DISABLED_PROPERTIES = [ + 'draggable', + 'setData', + 'supportPointer' +]; +```` + +Those properties will not be included in built file so you either need to manually set them in the element or make sure they aren't nescessary. + +### Editing template + +You can do whatever you want in the template file as long as you don't remove two comments: + +````javascript +/*properties*/ + +/*propertyobservers*/ +```` + +Those two must stay in their places and you mustn't forget they will be overwriten with normal property/function definiton - do not remove commas! + +## Pull Requests + +Before submitting a Pull Request be sure to run `build.js`. + +If you change the code, commit the same message both to the template and generated file if possible. + +If you change is only update to latest Sortable, update version in `bower.json` and commit your change as `Rebuilt for Sortable [verison-number]`. \ No newline at end of file diff --git a/build.js b/build.js new file mode 100644 index 0000000..f721c6d --- /dev/null +++ b/build.js @@ -0,0 +1,176 @@ +const DISABLED_PROPERTIES = [ + 'draggable', + 'setData', + 'supportPointer' +]; + + +const fsCallbacks = require('fs'), + path = require('path'), + https = require('https'), + promisify = require('util').promisify; + +const fs = { + stat: promisify(fsCallbacks.stat), + readFile: promisify(fsCallbacks.readFile), + writeFile: promisify(fsCallbacks.writeFile) +}; + +// From https://stackoverflow.com/a/17676794/6166832 +function donwload(url, dest) { + return new Promise((resolve, reject) => { + const file = fsCallbacks.createWriteStream(dest), + request = http.get(url, response => { + response.pipe(file); + file.on('finish', () => file.close(reslove)); + }); + }); +} + + +// Look for bower_components +fs.stat('bower_components/Sortable/Sortable.js').then(stat => { + loadFromFile('bower_components/Sortable/Sortable.js'); +}, err => { + if (err.code !== 'ENOENT') throw err + else { + // Look a level deeper + fs.stat('../bower_components/Sortable/Sortable.js').then(stat => { + loadFromFile('../bower_components/Sortable/Sortable.js'); + }, err => { + if (err.code !== 'ENOENT') throw err + // Look in node_modules + else fs.stat('node_modules/Sortable/Sortable.js').then(stat => { + loadFromFile('node_modules/Sortable/Sortable.js'); + }, err => { + if (err.code !== 'ENOENT') throw err + // Look in node_modules but deeper + else fs.stat('../node_modules/Sortable/Sortable.js').then(stat => { + loadFromFile('../node_modules/Sortable/Sortable.js'); + }, err => { + if (err.code !== 'ENOENT') throw err + else { + downloadFromGit(); + } + }); + }); + }); + } +}); + + +async function loadFromFile(filePath) { + const file = await fs.readFile(path.join(__dirname, filePath), 'utf8'); + proceed(file); +} + +async function downloadFromGit() { + const gitUsername = process.argv.includes('-u') + ? process.argv[process.argv.indexOf('-u') + 1] : 'RubaXa'; + const gitBranch = process.argv.includes('-b') + ? process.argv[process.argv.indexOf('-b') + 1] : 'master'; + https.get(`https://raw.githubusercontent.com/${gitUsername}/Sortable/${gitBranch}/Sortable.js`, resp => { +   let data = ''; +   resp.on('data', (chunk) => { +     data += chunk; +   }); +   resp.on('end', () => { +     proceed(data); +   }); + }).on("error", err => { +   console.trace(err); + throw new Error('Couldn\'t get Sortable.js'); + }); +} + +async function proceed(string) { + // Get options from source code of Sortblejs + const optionsString = /var\s+defaults\s*=\s*{\s*(([^:]+:[^,}]+)+\s*)}/m.exec(string)[1], + optionsStringSplit = optionsString.split(''), + optionsArray = []; + // Read them into an array [ key, value, key, value... ] + let current = '', + depthLevel = 0, + depthExpectColon = false, + depthStringOpen = false; + for (let i in optionsStringSplit) { + const character = optionsStringSplit[i]; + if (character === '{' + || (character === '\'' && !depthStringOpen) || (character === '"' && !depthStringOpen) + || character === '?' + || character === '(') { + depthLevel++; + if (character === '?') depthExpectColon = true; + if (character === '\'' || character === '"') depthStringOpen = true; + if (depthLevel > 0) current += character; + } else if (character === '}' + || (character === '\'' && depthStringOpen) || (character === '"' && depthStringOpen) + || (depthExpectColon && character === ':') + || character === ')') { + depthLevel--; + if (character === ':') depthExpectColon = false; + if (character === '\'' || character === '"') depthStringOpen = false; + if (depthLevel >= 0) current += character; + } else if ((character === ',' + || character === ':') + && depthLevel === 0) { + optionsArray.push(current); + current = ''; + } else if (depthLevel > 0 || /[^\s:,]/.test(character)) { + current += character; + } + if (depthLevel < 0) { + optionsArray.push(current); + break; + } + } + // Throw if read options aren't even + if (optionsArray.length % 2) { + console.log('Options that were read:', optionsArray); + throw new Error('Something went wrong when reading options'); + } + // Process the array to attach types + const computedOptions = {}; + let key, value, type; + optionsArray.forEach((item, index) => { + index % 2 ? value = item : key = item; + if (value && key) { + if (!DISABLED_PROPERTIES.includes(key)) { + if (value === 'false' || value === 'true') type = 'Boolean' + else if (Number(value) !== NaN) type = 'Number' + else if (/$\s*\{/.test(value)) type = 'Object' + else if (/$\s*\[/.test(value)) type = 'Array' + else type = 'String' + computedOptions[key] = { value, type }; + } + key = value = type = null; + } + }); + + // Get template file + const template = await fs.readFile(path.join(__dirname, 'polymer-sortablejs-template.html'), 'utf8'); + let generatedTemplate = template; + + // Generate properties + generatedTemplate = generatedTemplate.replace(/^(\s*)\/\*properties\*\//m, (_, spacing) => { + let output = ''; + for (key in computedOptions) { + const type = computedOptions[key].type, + value = computedOptions[key].value; + output += `${spacing}${key}: { type: ${type}, value: function() { return ${value} }, observer: '${key}Changed' },\n` + } + return output.slice(0, -2); + }); + + // Generate observers + generatedTemplate = generatedTemplate.replace(/^(\s*)\/\*propertyobservers\*\//m, (_, spacing) => { + let output = ''; + for (key in computedOptions) { + if (!new RegExp(key + 'Changed').test(template)) + output += `${spacing}${key}Changed: function(value) { this.sortable && this.sortable.option("${key}", value); },\n` + } + return output.slice(0, -2); + }); + + await fs.writeFile(path.join(__dirname, 'polymer-sortablejs.html'), generatedTemplate, 'utf8'); +} \ No newline at end of file From 91eb627562543d32462c0225d719b983bec56314 Mon Sep 17 00:00:00 2001 From: Wiktor Olejniczak Date: Fri, 9 Mar 2018 19:34:30 +0100 Subject: [PATCH 5/5] Upgraded build process Made it simpler, more informative and better at finding files --- build.js | 66 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/build.js b/build.js index f721c6d..ec76af6 100644 --- a/build.js +++ b/build.js @@ -13,7 +13,8 @@ const fsCallbacks = require('fs'), const fs = { stat: promisify(fsCallbacks.stat), readFile: promisify(fsCallbacks.readFile), - writeFile: promisify(fsCallbacks.writeFile) + writeFile: promisify(fsCallbacks.writeFile), + exists: fsCallbacks.existsSync }; // From https://stackoverflow.com/a/17676794/6166832 @@ -28,39 +29,43 @@ function donwload(url, dest) { } -// Look for bower_components -fs.stat('bower_components/Sortable/Sortable.js').then(stat => { - loadFromFile('bower_components/Sortable/Sortable.js'); -}, err => { - if (err.code !== 'ENOENT') throw err - else { - // Look a level deeper - fs.stat('../bower_components/Sortable/Sortable.js').then(stat => { - loadFromFile('../bower_components/Sortable/Sortable.js'); - }, err => { - if (err.code !== 'ENOENT') throw err - // Look in node_modules - else fs.stat('node_modules/Sortable/Sortable.js').then(stat => { - loadFromFile('node_modules/Sortable/Sortable.js'); - }, err => { - if (err.code !== 'ENOENT') throw err - // Look in node_modules but deeper - else fs.stat('../node_modules/Sortable/Sortable.js').then(stat => { - loadFromFile('../node_modules/Sortable/Sortable.js'); - }, err => { - if (err.code !== 'ENOENT') throw err - else { - downloadFromGit(); - } - }); - }); - }); +// Helper for folder lookup +function generatePath(depth, ending) { + const generatedDepth = new Array(depth).fill('..'); + return path.join(__dirname, ...generatedDepth, ending); +} + +let found = false; + +// Look in bower_components +for (let depth = 0; depth <= 2; depth++) { + if (fs.exists(generatePath(depth, 'bower_components/Sortable/Sortable.js'))) { + found = true; + console.log('Building from version in bower_components'); + loadFromFile(generatePath(depth, 'bower_components/Sortable/Sortable.js')); + break; + } +} + +if (!found) { + // Look in node_modules + for (let depth = 0; depth <= 2; depth++) { + if (fs.exists(generatePath(depth, 'node_modules/Sortable/Sortable.js'))) { + found = true; + console.log('Building from version in node_modules'); + loadFromFile(generatePath(depth, 'node_modules/Sortable/Sortable.js')); + break; } -}); + } +} + +if (!found) { + downloadFromGit(); +} async function loadFromFile(filePath) { - const file = await fs.readFile(path.join(__dirname, filePath), 'utf8'); + const file = await fs.readFile(filePath, 'utf8'); proceed(file); } @@ -81,6 +86,7 @@ async function downloadFromGit() {   console.trace(err); throw new Error('Couldn\'t get Sortable.js'); }); + console.log(`Building from Gtihub ${gitUsername}/Sortable#${gitBranch}`); } async function proceed(string) {