2018-03-30 17:08:09 -05:00
|
|
|
<template>
|
2018-09-09 16:37:25 -05:00
|
|
|
<span class="icon" :class="sizeClass" @click="$emit('click', $event)" ref="container">
|
|
|
|
|
2018-03-30 17:08:09 -05:00
|
|
|
</span>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
2018-08-29 16:58:07 -05:00
|
|
|
|
|
|
|
import IconicJs from "../iconic/js/iconic.min";
|
|
|
|
|
|
|
|
import Caret from "../iconic/svg/smart/caret";
|
|
|
|
import Check from "../iconic/svg/smart/check";
|
|
|
|
import CircleCheck from "../iconic/svg/smart/circle-check";
|
|
|
|
import Link from "../iconic/svg/smart/link";
|
|
|
|
import Lock from "../iconic/svg/smart/lock";
|
2018-09-07 21:56:13 -05:00
|
|
|
import Menu from "../iconic/svg/smart/menu";
|
2018-08-29 16:58:07 -05:00
|
|
|
import Person from "../iconic/svg/smart/person";
|
|
|
|
import Pencil from "../iconic/svg/smart/pencil";
|
|
|
|
import Star from "../iconic/svg/smart/star";
|
|
|
|
import StarEmpty from "../iconic/svg/smart/star-empty";
|
|
|
|
import X from "../iconic/svg/smart/x";
|
2018-09-09 16:37:25 -05:00
|
|
|
|
|
|
|
const SVG_CACHE = {};
|
|
|
|
let REMAP_COUNT = 0;
|
2018-08-29 16:58:07 -05:00
|
|
|
|
|
|
|
class IconData {
|
2018-09-09 16:37:25 -05:00
|
|
|
constructor(svgData, dataAttributes) {
|
|
|
|
this.svgData = svgData;
|
2018-09-07 21:56:13 -05:00
|
|
|
this.dataAttributes = dataAttributes || {};
|
2018-09-09 16:37:25 -05:00
|
|
|
this.svgTemplate = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
getSvg() {
|
|
|
|
if (this.svgTemplate === null) {
|
|
|
|
const iconicName = this.svgData.attributes.class;
|
|
|
|
|
|
|
|
this.svgTemplate = SVG_CACHE[iconicName] || null;
|
|
|
|
|
|
|
|
if (this.svgTemplate === null) {
|
|
|
|
this.svgTemplate = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
|
|
SVG_CACHE[iconicName] = this.svgTemplate;
|
|
|
|
|
|
|
|
for (let attr in this.svgData.attributes) {
|
|
|
|
this.svgTemplate.setAttribute(attr, this.svgData.attributes[attr]);
|
|
|
|
}
|
|
|
|
this.svgTemplate.innerHTML = this.svgData.content;
|
|
|
|
|
|
|
|
|
|
|
|
// Find then prune the scripts
|
|
|
|
const scripts = [...this.svgTemplate.querySelectorAll('script')];
|
|
|
|
|
|
|
|
scripts.filter(s => {
|
|
|
|
let scriptType = s.getAttribute("type");
|
|
|
|
return !scriptType || scriptType === 'application/ecmascript' || scriptType === 'application/javascript'
|
|
|
|
}).forEach(s => {
|
|
|
|
new Function(s.innerText || s.textContent)(window);
|
|
|
|
this.svgTemplate.removeChild(s);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const clone = this.svgTemplate.cloneNode(true);
|
|
|
|
this.remapIds(clone);
|
|
|
|
this.attachIconicApi(clone);
|
|
|
|
for (let attr in this.dataAttributes) {
|
|
|
|
clone.setAttribute(`data-${attr}`, this.dataAttributes[attr]);
|
|
|
|
}
|
|
|
|
return clone;
|
|
|
|
}
|
|
|
|
|
|
|
|
remapIds(svg) {
|
|
|
|
const iriElementsAndProperties = {
|
|
|
|
'clipPath': ['clip-path'],
|
|
|
|
'color-profile': ['color-profile'],
|
|
|
|
'cursor': ['cursor'],
|
|
|
|
'filter': ['filter'],
|
|
|
|
'linearGradient': ['fill', 'stroke'],
|
|
|
|
'marker': ['marker', 'marker-start', 'marker-mid', 'marker-end'],
|
|
|
|
'mask': ['mask'],
|
|
|
|
'pattern': ['fill', 'stroke'],
|
|
|
|
'radialGradient': ['fill', 'stroke']
|
|
|
|
};
|
|
|
|
|
|
|
|
REMAP_COUNT += 1;
|
|
|
|
|
|
|
|
let element, elementDefs, properties, currentId, newId;
|
|
|
|
Object.keys(iriElementsAndProperties).forEach(function (key) {
|
|
|
|
element = key;
|
|
|
|
properties = iriElementsAndProperties[key];
|
|
|
|
|
|
|
|
elementDefs = svg.querySelectorAll('defs ' + element + '[id]');
|
|
|
|
for (var i = 0, elementsLen = elementDefs.length; i < elementsLen; i++) {
|
|
|
|
currentId = elementDefs[i].id;
|
|
|
|
newId = currentId + '-' + REMAP_COUNT;
|
|
|
|
|
|
|
|
// All of the properties that can reference this element type
|
|
|
|
var referencingElements;
|
|
|
|
properties.forEach(function (property) {
|
|
|
|
// :NOTE: using a substring match attr selector here to deal with IE "adding extra quotes in url() attrs"
|
|
|
|
referencingElements = svg.querySelectorAll('[' + property + '*="' + currentId + '"]');
|
|
|
|
for (var j = 0, referencingElementLen = referencingElements.length; j < referencingElementLen; j++) {
|
|
|
|
referencingElements[j].setAttribute(property, 'url(#' + newId + ')');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
elementDefs[i].id = newId;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
attachIconicApi(svg) {
|
|
|
|
const key = svg.getAttribute("data-icon");
|
|
|
|
const apis = window.iconicSmartIconApis;
|
|
|
|
if (key && apis[key]) {
|
|
|
|
const iconApi = apis[key](svg);
|
|
|
|
for (let func in iconApi) svg[func] = iconApi[func]
|
|
|
|
}
|
2018-08-29 16:58:07 -05:00
|
|
|
}
|
|
|
|
}
|
2018-03-30 17:08:09 -05:00
|
|
|
|
2018-08-29 16:58:07 -05:00
|
|
|
class SizeData {
|
|
|
|
constructor(bulmaIconClass, defaultPadding) {
|
|
|
|
this.bulmaIconClass = bulmaIconClass;
|
2018-09-05 11:00:35 -05:00
|
|
|
this.defaultPadding = defaultPadding || null;
|
2018-08-29 16:58:07 -05:00
|
|
|
}
|
|
|
|
}
|
2018-09-09 16:37:25 -05:00
|
|
|
|
|
|
|
class IconicQueue {
|
|
|
|
constructor(iconicInstance) {
|
|
|
|
this.iconic = iconicInstance;
|
|
|
|
this.updateQueue = [];
|
|
|
|
this.isTimerRunning = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
processQueues() {
|
|
|
|
if (this.updateQueue.length > 0) {
|
|
|
|
console.log(`updating ${this.updateQueue.length}`);
|
|
|
|
this.iconic.update(this.updateQueue);
|
|
|
|
this.updateQueue.forEach(s => (s.style.visibility = null));
|
|
|
|
this.updateQueue = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
this.isTimerRunning = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ensureTimer() {
|
|
|
|
if (!this.isTimerRunning) {
|
|
|
|
this.isTimerRunning = true;
|
|
|
|
setTimeout(() => this.processQueues());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updateSvg(svgElem) {
|
|
|
|
this.updateQueue.push(svgElem);
|
|
|
|
this.ensureTimer();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const iconicInstance = IconicJs({
|
|
|
|
autoInjectSelector: "#notreal-noinjection"
|
|
|
|
});
|
|
|
|
|
|
|
|
const iconicQueue = new IconicQueue(iconicInstance);
|
2018-08-29 16:58:07 -05:00
|
|
|
|
2018-03-30 17:08:09 -05:00
|
|
|
const iconMap = {
|
2018-08-29 16:58:07 -05:00
|
|
|
'caret-bottom': new IconData(Caret, {direction: 'bottom'}),
|
|
|
|
'caret-top': new IconData(Caret, {direction: 'top'}),
|
|
|
|
check: new IconData(Check),
|
|
|
|
'circle-check': new IconData(CircleCheck),
|
|
|
|
'link-broken': new IconData(Link, {state: 'broken'}),
|
|
|
|
'link-intact': new IconData(Link, {state: 'intact'}),
|
|
|
|
'lock-locked': new IconData(Lock, {state: 'locked'}),
|
|
|
|
'lock-unlocked': new IconData(Lock, {state: 'unlocked'}),
|
2018-09-07 21:56:13 -05:00
|
|
|
menu: new IconData(Menu),
|
2018-08-29 16:58:07 -05:00
|
|
|
pencil: new IconData(Pencil),
|
|
|
|
person: new IconData(Person),
|
|
|
|
star: new IconData(Star),
|
|
|
|
'star-empty': new IconData(StarEmpty),
|
|
|
|
x: new IconData(X)
|
2018-03-30 17:08:09 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
const sizeMap = {
|
2018-09-07 21:56:13 -05:00
|
|
|
xs: new SizeData('is-small', '25%'),
|
2018-09-05 11:00:35 -05:00
|
|
|
sm: new SizeData('is-small'),
|
|
|
|
md: new SizeData(''),
|
|
|
|
lg: new SizeData('is-medium'),
|
|
|
|
xl: new SizeData('is-large')
|
2018-03-30 17:08:09 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
export default {
|
|
|
|
props: {
|
|
|
|
icon: {
|
|
|
|
validator: (i) => iconMap[i] !== undefined
|
|
|
|
},
|
|
|
|
size: {
|
|
|
|
required: false,
|
|
|
|
type: String,
|
|
|
|
validator: (s) => sizeMap[s] !== undefined,
|
|
|
|
default: 'md'
|
2018-08-29 16:58:07 -05:00
|
|
|
},
|
|
|
|
padding: {
|
|
|
|
type: String,
|
|
|
|
required: false,
|
|
|
|
default: null
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
injectedSvg: null
|
2018-03-30 17:08:09 -05:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
computed: {
|
2018-08-29 16:58:07 -05:00
|
|
|
iconData() {
|
2018-03-30 17:08:09 -05:00
|
|
|
return iconMap[this.icon];
|
|
|
|
},
|
|
|
|
|
2018-09-05 11:00:35 -05:00
|
|
|
sizeData() {
|
|
|
|
return sizeMap[this.size];
|
|
|
|
},
|
|
|
|
|
2018-08-29 16:58:07 -05:00
|
|
|
sizeClass() {
|
2018-09-05 11:00:35 -05:00
|
|
|
return this.sizeData.bulmaIconClass;
|
2018-08-29 16:58:07 -05:00
|
|
|
},
|
2018-03-30 17:08:09 -05:00
|
|
|
|
2018-09-05 11:00:35 -05:00
|
|
|
svgPadding() {
|
|
|
|
return this.padding || this.sizeData.defaultPadding || "15%";
|
2018-04-03 18:31:20 -05:00
|
|
|
}
|
2018-08-29 16:58:07 -05:00
|
|
|
},
|
2018-04-03 18:31:20 -05:00
|
|
|
|
2018-09-09 16:37:25 -05:00
|
|
|
methods: {
|
|
|
|
insertSvg() {
|
|
|
|
const parent = this.$refs.container;
|
|
|
|
|
|
|
|
while (parent.firstChild) {
|
|
|
|
parent.removeChild(parent.firstChild);
|
|
|
|
}
|
|
|
|
|
|
|
|
const svg = this.iconData.getSvg();
|
|
|
|
this.injectedSvg = svg;
|
|
|
|
|
|
|
|
svg.style.padding = this.svgPadding;
|
|
|
|
svg.style.visibility = "hidden";
|
|
|
|
svg.classList.add("iconic-fluid");
|
|
|
|
parent.appendChild(svg);
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
//svg.style.visibility = "visible";
|
|
|
|
//iconicInstance.update(svg);
|
|
|
|
iconicQueue.updateSvg(svg);
|
2018-09-07 21:56:13 -05:00
|
|
|
});
|
2018-09-09 16:37:25 -05:00
|
|
|
}
|
2018-08-29 16:58:07 -05:00
|
|
|
},
|
2018-03-30 17:08:09 -05:00
|
|
|
|
2018-09-09 16:37:25 -05:00
|
|
|
mounted() {
|
|
|
|
let self = this;
|
|
|
|
this.$watch(
|
|
|
|
function() { return this.icon + this.size + this.padding },
|
|
|
|
function() {
|
|
|
|
this.insertSvg();
|
|
|
|
},
|
|
|
|
{
|
|
|
|
immediate: true
|
2018-09-07 21:56:13 -05:00
|
|
|
}
|
2018-09-09 16:37:25 -05:00
|
|
|
)
|
2018-08-29 16:58:07 -05:00
|
|
|
}
|
|
|
|
}
|
2018-03-30 17:08:09 -05:00
|
|
|
|
2018-08-29 16:58:07 -05:00
|
|
|
</script>
|
2018-03-30 17:08:09 -05:00
|
|
|
|
2018-08-29 16:58:07 -05:00
|
|
|
<style lang="scss" scoped>
|
2018-03-30 17:08:09 -05:00
|
|
|
|
2018-09-05 11:00:35 -05:00
|
|
|
|
2018-03-30 17:08:09 -05:00
|
|
|
|
|
|
|
</style>
|