diff --git a/.gitignore b/.gitignore index e9bcd3d..8b25c21 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,201 @@ node_modules out .DS_Store + +# Packed Extension and Certificates +*.crx +*.pem + +# Created by https://www.gitignore.io/api/node +# Edit at https://www.gitignore.io/?templates=node + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# react / gatsby +public/ + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# End of https://www.gitignore.io/api/node + + + +# Created by https://www.gitignore.io/api/jetbrains +# Edit at https://www.gitignore.io/?templates=jetbrains + +### JetBrains ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### JetBrains Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/**/sonarlint/ + +# SonarQube Plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator/ + +# End of https://www.gitignore.io/api/jetbrains + diff --git a/package-lock.json b/package-lock.json index e4560a8..bc4bb36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "re-view-chrome", - "version": "2.1.7", + "version": "2.1.8", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9cc0e4b..b5947e3 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,14 @@ { "name": "re-view-chrome", - "version": "2.1.7", + "version": "2.1.8", "description": "Emmet Re:view extension for Google Chrome", "main": "index.js", + "engines" : { "node" : "~8.10.0" }, "scripts": { + "build": "gulp", "publish": "NODE_ENV=production gulp pack", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "watch": "gulp watch" }, "repository": { "type": "git", @@ -18,6 +21,13 @@ "view" ], "author": "Sergey Chikuyonok ", + "contributors": [ + { + "name": "JamesCodesThings", + "email": "jamescodesthings@gmail.com", + "url": "https://github.com/jamescodesthings" + } + ], "license": "ISC", "bugs": { "url": "https://github.com/emmetio/re-view-chrome/issues" diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..5d6055f --- /dev/null +++ b/readme.md @@ -0,0 +1,14 @@ +# Emmet Review (2) +https://chrome.google.com/webstore/detail/emmet-review/epejoicbhllgiimigokgjdoijnpaphdp?hl=en + +Fork from: https://github.com/PacktDev/re-view-chrome + +# Local Development +1. Clone +2. `npm i` +3. `npm run watch` +4. Goto `chrome://extensions` +5. Load unpacked extension +6. Load the `out` folder + +When done, pack, do whatever, happy days. diff --git a/scripts/lib/find-breakpoints.js b/scripts/lib/find-breakpoints.js new file mode 100644 index 0000000..405dcf5 --- /dev/null +++ b/scripts/lib/find-breakpoints.js @@ -0,0 +1,199 @@ +/** + * Scans media query breakpoints in given CSSStylesheet and returns + * them as array + */ +'use strict'; +const allowedFeatures = ['min-width', 'max-width']; + +export default function(doc=document, options={}) { + + var list = Array.from(doc.styleSheets); + return Promise.all(list.map(ss => { + // NB Check for own `.cssRules` property to bypass Chrome security + // with external stylesheets + // try...catch because browser may not able to enumerate rules for cross-domain sheets + + try { + const rules = ss.rules || ss.cssRules; + if (rules) return readCSSOM(ss); + } catch (e) { + console.warn("Can't read the css rules of: " + ss.href, e); + } + + // Rules are not available: most likely CSS was loaded + // from another domain and browser blocked access to CSSOM + // according to same-origin policy. + // Try to use external loader, if available + if (options.loadCSS) { + return options.loadCSS(ss.href).then(readCSSOM); + } + + return null; + })) + // flatten nested arrays of breakpoints + .then(values => [].concat(...values.filter(Boolean))) + .then((array) => { + var uniqueArray = unique(array); + return uniqueArray; + }) + .then(optimize) + .then(bp => bp.sort((a, b) => a.smallest - b.smallest)); +}; + +class Breakpoint { + constructor(query, features) { + this._real = null; + this._id = null; + this._features = null; + this._query = query.trim(); + this.features = features; + } + + get id() { + if (this._id === null && this.features.length) { + this._id = 'bp_' + this.features.map(f => f + this[f]).join('__'); + } + + return this._id; + } + + get query() { + return this._query; + } + + get features() { + if (!this._features) { + this._features = Object.keys(this).filter(key => key[0] !== '_').sort(); + } + + return this._features; + } + + set features(value={}) { + this._id = this._features = this._real = null; + Object.keys(value).forEach(feature => this[normalizeName(feature)] = value[feature]); + } + + /** + * Returns smallest feature size for current breakpoint + * @type {Number} + */ + get smallest() { + var smallest = this.features.reduce((prev, f) => Math.min(prev, this.real(f)), Number.POSITIVE_INFINITY); + return smallest !== Number.POSITIVE_INFINITY ? smallest : 0; + } + + /** + * Returns real size (in pixels) of given feature + * @param {String} feature + */ + real(feature) { + if (!this._real) { + this.measure(); + } + + return this._real[normalizeName(feature)]; + } + + /** + * Measures real feature's dimentions + * @param {Element} ctx Optional content element where + * features should be measured + * @return {Object} Real feature sizes + */ + measure(ctx=document.body) { + var m = document.createElement('div'); + m.style.cssText = 'position:absolute;padding:0;margin:0;top:0;left:0;height:0;'; + ctx.appendChild(m); + + var real = this.features.reduce((out, feature) => { + if (typeof this[feature] === 'number') { + out[feature] = this[feature]; + } else { + m.style.width = this[feature]; + out[feature] = m.offsetWidth; + } + return out; + }, {}); + + ctx.removeChild(m); + return this._real = real; + } +} + +/** + * Parses media query expression and returns breakpoint + * options + * @param {String} mq Media Query expression + * @return {Breakpoint} + */ +function parse(mq) { + var feature, out = {}, empty = true; + mq.replace(/\(\s*([\w\-]+)\s*:\s*(.+?)\)/g, function(str, feature, value) { + feature = feature.trim(); + if (allowedFeatures.indexOf(feature) !== -1) { + empty = false; + out[feature] = value.trim(); + } + return ''; + }); + + return empty ? null : new Breakpoint(mq, out); +} + +function readCSSOM(stylesheet, breakpoints=[]) { + var rules = stylesheet.rules || stylesheet.cssRules; + + // Have Found Media Query? + var found = false; + + for (var i = 0, il = rules.length; i < il; i++) { + if (rules[i].media) { + var cssMediaList = rules[i].media; + found = true; + for (var j = 0, jl = cssMediaList.length; j < jl; j++) { + var mediaRule = parse(cssMediaList[j]); + if(mediaRule) breakpoints.push(mediaRule); + } + } + + if (rules[i].styleSheet) { + readCSSOM(rules[i].styleSheet, breakpoints); + } + } + + if(!found) console.warn('Did not find any media queries in', stylesheet.href || stylesheet); + + return breakpoints; +} + +/** + * Filters given breakpoints list and leaves unique items only + * @param {Array} breakpoints + * @return {Array} + */ +function unique(breakpoints) { + var lookup = {}; + return breakpoints.filter(b => !b || lookup[b.id] ? false : lookup[b.id] = true); +} + +function normalizeName(str) { + return str.replace(/\-([a-z])/g, (str, ch) => ch.toUpperCase()); +} + +/** + * Optimizes breakpoints list: keeps only ones with unique width + * @param {Array} breakpoints + * @return {Array} + */ +function optimize(breakpoints) { + var lookup = {} + return breakpoints.reduce((out, bp) => { + var width = bp.smallest; + if (!lookup[width]) { + lookup[width] = true; + out.push(bp); + } + return out; + }, []); +} diff --git a/scripts/re-view.js b/scripts/re-view.js index 1379975..9251098 100644 --- a/scripts/re-view.js +++ b/scripts/re-view.js @@ -1,8 +1,10 @@ 'use strict'; -import {default as reView, dispatch, subscribe, findBreakpoints, getStateValue, UI, APP, DONATION} from 'livestyle-re-view'; +import {default as reView, dispatch, subscribe, getStateValue, UI, APP, DONATION} from 'livestyle-re-view'; import {throttle} from './lib/utils'; import * as donation from './lib/donation'; +import findBreakpoints from './lib/find-breakpoints'; + const storage = chrome.storage.sync; const storageKey = 're-view2'; const donatedKey = 'donated';