Skip to content

Commit 277dfbf

Browse files
committed
V 0.1 alpha
Initial alpha release
1 parent d364e61 commit 277dfbf

File tree

4 files changed

+1004
-0
lines changed

4 files changed

+1004
-0
lines changed

README.md

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
###SHAPE.JS
2+
3+
**Shape.js** is a lightweight Javascript tool to create invisible shape around which content flows. It is inspired by [CSS Exclusions](http://caniuse.com/#feat=css-exclusions) ([W3C draft](https://www.w3.org/TR/css3-exclusions/)). It features basic hyphenation, support for [Hypher.js](https://github.com/bramstein/hypher), all this without dependencies.
4+
5+
You can see a live demo [here](jdmcreator.github.io/lab/shapejs/demo.html).
6+
7+
Version 0.1 alpha
8+
9+
#### Support
10+
11+
**Chrome** : Supported
12+
**Firefox** : Supported
13+
**Edge** : Supported
14+
**IE 10+** : Supported
15+
16+
*SHAPE.JS results on Edge/IE10+ are degrading a little.*
17+
18+
#### Documentation
19+
20+
##### SHAPE object
21+
22+
You can access the SHAPE object using `window.SHAPE`
23+
24+
###### Properties
25+
26+
**refreshOnResize** : `Boolean`. Whether shapes should be refreshed on window resize. (default : true)
27+
28+
###### Methods
29+
30+
**changeDefaultHyphenCharacter(string character)**
31+
32+
Change all hyphen characters to `character`. The default character is U+002D (-).
33+
```javascript
34+
window.SHAPE.changeDefaultHyphenCharacter("\u2010");
35+
```
36+
37+
**forEach(function fn)**
38+
39+
Call the function `fn` for each shape registered, with the `SHAPEObject` as `this`. If the function `fn` return a false value that is not `undefined`, the loop stops.
40+
```javascript
41+
window.SHAPE.forEach(function(){
42+
console.log(this.id);
43+
});
44+
```
45+
46+
47+
**refreshAll(boolean force)**
48+
49+
Refresh every shape. If `force` is set to `true`, the result should be perfect, but will take longer.
50+
51+
*You should always set `force` to `true`.*
52+
53+
```javascript
54+
window.SHAPE.refreshAll(true);
55+
```
56+
57+
**removeAll(** Optional `HTMLElement` **element )**
58+
59+
Remove every shape from the document and normalize `element` (or `document.body`)
60+
61+
```javascript
62+
window.SHAPE.removeAll(true);
63+
```
64+
65+
##### SHAPEObject object
66+
67+
You can create a `SHAPEObject` Object using `window.SHAPE(options)`.
68+
69+
###### Options
70+
71+
**height** : `Number`. Height of the shape, in pixels.
72+
**hyphenation** : *Optional*. `Function`. Function that will define hyphenation rules for the document. See the section relative to hyphenation for more information.
73+
**hyphenCharacter** : *Optional*. `String`. Hyphen character. If not specified, the default hyphen character is used (See `SHAPE.changeDefaultHyphenCharacter`).
74+
**left** : `Number`. Position of the shape relative to the left of the document, in pixels.
75+
**margin** : *Optional*. `Number`. Margin of the shape, in pixels.
76+
**top** : `Number`. Position of the shape relative to the top of the document, in pixels.
77+
**width** : `Number`. Width of the shape, in pixels.
78+
79+
```javascript
80+
var myshape = window.SHAPE({
81+
left : 25,
82+
top: 25,
83+
width: 50,
84+
height : 50,
85+
// Optional values are next
86+
margin : 5,
87+
hyphenation : window.SHAPE.HYPHENATION.NH_WORD
88+
});
89+
```
90+
91+
###### Properties
92+
93+
**id** : `String`. Autogenerated ID of the shape.
94+
**shape** : `Object`. Object with **bottom**, **left**, **right** and **top** properties.
95+
96+
###### Methods
97+
98+
**applyToNodes(**`Misc` **element1, **`Misc` **element2, ..., **`Misc` **elementN)**
99+
100+
Apply the shape to each node specified in the function arguments. `Misc` means each argument can be an `Array`, a `HTMLElement`, a `TextNode` or a `NodeList`.
101+
102+
```javascript
103+
var element = document.getElementById('element');
104+
window.requestAnimationFrame(function(){
105+
myshape.applyToNodes(
106+
element,
107+
element.nextSibling.querySelectorAll("p")
108+
);
109+
});
110+
```
111+
112+
```javascript
113+
window.requestAnimationFrame(function(){
114+
myshape.applyToNodes(document.body);
115+
});
116+
```
117+
118+
*You should use *`window.requestAnimationFrame` *when calling this function because of its heavy use of ressources.*
119+
120+
**cleanMemory()**
121+
122+
Cleans the internal memory of SHAPE.JS to reflect changes to the DOM. It allows `SHAPEObject.refresh()` to works as expected.
123+
124+
```javascript
125+
myshape.cleanMemory();
126+
```
127+
128+
*You should call* `cleanMemory()` *every time you make yourself changes to the DOM that affects the invisible shape.*
129+
130+
**destroy()**
131+
132+
Remove every references to the instance from `window.shape`.
133+
```javascript
134+
myshape.destroy();
135+
```
136+
137+
**refresh()**
138+
139+
Refresh the shape for minor changes.
140+
```javascript
141+
myshape.refresh();
142+
```
143+
144+
To force a full refresh, you should call `SHAPE.refreshAll(true)` or `shape.applyToNodes` this way :
145+
146+
```javascript
147+
myshape.remove()
148+
.resetMemory()
149+
.applyToNodes(elements);
150+
```
151+
152+
**remove(** *Optional* `HTMLElement` **element,**
153+
*Optional* `Boolean` **leaveAsIt)**
154+
155+
Un-apply the shape from `HTMLElement` **element** (or from the document if non-specified) and then refresh other shapes that could be affected unless **leaveAsIt** is set to `true`.
156+
157+
```javascript
158+
myshape.remove(document.getElementById('my_element'));
159+
```
160+
161+
You can use this code to force a full refresh after you un-applied a shape from an element.
162+
163+
```javascript
164+
shape.remove(element, true);
165+
SHAPE.refreshAll(true);
166+
```
167+
168+
##### SHAPE.JS and Hyphenation
169+
170+
SHAPE.JS comes with a basic support for hyphenation. You can use one of the very basic built-in hyphenation, include [Hypher.js](https://github.com/bramstein/hypher) or use your own hyphenation function.
171+
172+
###### Hyphenation function
173+
174+
The `hyphenation` property of the option object of a `SHAPEObject` is a function that is called with two parameters : the word and the maximum offset.
175+
176+
The function must returns the offset of the character before which the word will be split and a hyphen inserted if necessary. If the returned offset is higher than the maximum offset, the maximum offset will be used instead.
177+
178+
Example :
179+
180+
```javascript
181+
var hyphenationFunction = function(word, maxoffset){
182+
if(word == "prototype"){
183+
if(maxoffset < 3){
184+
return 0;
185+
}
186+
else if(maxoffset < 6){
187+
return 3; // pro-totype
188+
}
189+
else{
190+
return 6; // proto-type
191+
}
192+
}
193+
else{
194+
return 0;
195+
}
196+
}
197+
```
198+
199+
###### Built-in hyphenation functions
200+
201+
You can access built-in functions via `window.SHAPE.HYPHENATION`.
202+
203+
**ANYWHERE**
204+
205+
Cut the word anywhere and insert a hyphen if necessary.
206+
207+
``` none
208+
This is a prot|otype.
209+
---->
210+
This is a prot-[ ]otype
211+
```
212+
213+
**HYPHER(** `HypherInstance` **hypherInstance)**
214+
215+
Hyphenate the word using [Hypher.js](https://github.com/bramstein/hypher). Unlike others options, you must call `SHAPE.HYPHENATION.HYPHER` with an instance of Hypher as an argument.
216+
217+
```javascript
218+
var hypherinstance = new Hypher(Hypher.english);
219+
var myshape = window.SHAPE({
220+
left : 25,
221+
top: 25,
222+
width: 50,
223+
height : 50,
224+
hyphenation : window.SHAPE.HYPHENATION.HYPHER(hypherinstance)
225+
});
226+
```
227+
228+
``` none
229+
This is a prot|otype.
230+
---->
231+
This is a pro-[ ]totype
232+
```
233+
*To use Hypher, you must use language patterns from [Hyphenator.js](https://github.com/mnater/Hyphenator/tree/master/patterns). You have to modify the language pattern js file to only use the language object part.*
234+
235+
**NH_ANYWHERE**
236+
237+
Default behavior. Cut the word anywhere and never insert hyphens.
238+
239+
``` none
240+
This is a prot|otype.
241+
---->
242+
This is a prot[ ]otype
243+
```
244+
245+
**NH_WORD**
246+
247+
Don't cut word and never insert hyphens.
248+
249+
``` none
250+
This is a prot|otype.
251+
---->
252+
This is a [ ]prototype
253+
```
254+
255+
#### License
256+
257+
SHAPE.JS is licensed under MIT License.

changelog.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Version 0.1 Alpha
2+
=================
3+
4+
+ Initial release

shape-min.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**********************/
2+
/* SHAPE.js */
3+
/* JDMCreator, 2016 */
4+
/* Under MIT License */
5+
/* V 0.1a */
6+
/**********************/
7+
!function(){"use strict"
8+
var e,t=void 0,n=window.document,r=function(e){return new s(e)},i=function(e){return!e&&0!==e&&""!==e&&"0"!==e},o=1e3,a={},s=function(e){if(i(e.top)||i(e.left)||i(e.width)||i(e.height))throw""
9+
this.options=e,this.id="S"+o++,i(e.hyphenCharacter)||_.insertRule('.SHAPE-hyphen[data-shape-id="'+this.id+"\"]::before { content:'"+e.hyphenCharacter+"'; }",_.rules.length),this.destroy=function(){this.remove(),delete a[this.id],r=t
10+
for(var e in this)this.hasOwnProperty(e)&&delete this[e]},this.remove=function(e,t){e=e||n
11+
var r=null,i=n.createRange(),o=e.querySelectorAll("[data-shape-id='"+this.id+"']")
12+
i.setStartBefore(o[0]),i.setEndAfter(o[1]),r=i.commonAncestorContainer,i.detach()
13+
for(var s,h=0,l=o.length;l>h;h++)s=o[h],v(s).removeChild(s)
14+
if(this.cleanMemory(),!t){o=r.querySelectorAll("[data-shape-id]")
15+
for(var s,f={},h=0,l=o.length;l>h;h++){s=o[h]
16+
var d=s.getAttribute("data-shape-id")
17+
if(!f[d]){f[d]=!0
18+
var u=a[d]
19+
u&&u.refresh()}}}return this},this._memory=[],this.resetMemory=function(){return this._memory=[],this},this.cleanMemory=function(){for(var e,t=[],n=0;n<this._memory.length;n++)e=this._memory[n],e.querySelectorAll("[data-shape-id='"+this.id+"']").length>0&&t.push(e)
20+
return this._memory=t,this},this.refresh=function(){return n.body.normalize(),this.applyToNodes(this._memory),this},this.applyToNodes=function(e){e=e||n.elementFromPoint(l,h)
21+
for(var t,r=0,i=Math.max(arguments.length,1);i>r;r++){t=0===r?e:arguments[r],t=t.length||0===t.length?t:[t]
22+
for(var o,a=0;a<t.length;a++)o=t[a],(1==o.nodeType||3==o.nodeType)&&s(o)}return this},this.shape=d
23+
var r=this,s=function(e){for(var t=!1,i=0;i<r._memory.length;i++)e===r._memory[i]&&(t=!0)
24+
t||r._memory.push(e)
25+
var o=y(e)
26+
o.push(r),o=o.sort(function(e,t){e.left-t.left}),A(e,e,o,function(e,t,r){var i,o=!1
27+
if(3==e.nodeType){if(this.options.hyphenation){var a=u(this.options.hyphenation,e,t)
28+
a&&(e=a.node,t=a.offset,o=a.hyphen)}t>0&&(e=e.splitText(t),i=n.createRange(),i.setStart(e,0),i.setEnd(e,1),r=f(i.getBoundingClientRect()))}var s=m(this.id),h=this.shape.right-r.left+1
29+
if(0===h)return e
30+
var l
31+
if(e.previousSibling){var d=e.previousSibling
32+
1==d.nodeType&&d.hasAttribute("data-shape-id")&&(o=!1)}return o?(s.className="SHAPE-hyphen",v(e).insertBefore(s,e),s.style.paddingRight=h-s.offsetWidth+1+"px",l=f(s.getBoundingClientRect())):(s.style.paddingRight=h+"px",v(e).insertBefore(s,e),l=f(s.getBoundingClientRect())),s.shape={o:this,left:l.left,right:l.right},i&&i.detach(),s})},h=e.top-(e.margin||0),l=e.left-(e.margin||0),d=(e.width+(e.margin||0),e.height+(e.margin||0),{top:h,left:l,right:l+e.width+2*(e.margin||0),bottom:h+e.height+2*(e.margin||0)})
33+
this.shape=d,a[this.id]=this
34+
this.id},h=function(e,n,r){var i=/\s+/gi
35+
n||0===n||(n=e.data.length-1)
36+
for(var o=[e],a=[],s=n;s>=0;s--)if(a=[r.startContainer,r.startOffset],r.setStart(e,s),i.test(""+r))return r.setStart(a[0],a[1]),{nodes:o,word:!0}
37+
var l=g(e)
38+
if(l){var f=h(l,t,r)
39+
if(o=o.concat(f.nodes),f.word)return{nodes:o,word:!0}}return{nodes:o,word:!1}},l=function(e,t,n){for(var r=/\s+/gi,t=t||0,i=[e],o=[],a=t;a<e.data.length;a++)if(o=[n.endContainer,n.endOffset],n.setEnd(e,a),r.test(""+n))return n.setEnd(o[0],o[1]),{nodes:i,word:!0}
40+
var s=p(e)
41+
if(s){var h=l(s,0,n)
42+
if(i=i.concat(h.nodes),h.word)return{nodes:i,word:!0}}return{nodes:i,word:!1}},f=function(t){if(!n.body)return t
43+
e||(e=n.createElement("div"),e.style.position="absolute",e.style.left=e.style.top="0",n.body.appendChild(e))
44+
var r=e.getBoundingClientRect()
45+
return{top:t.top-r.top,left:t.left-r.left,right:t.right-r.right,bottom:t.bottom-r.bottom,width:t.width,height:t.height}},d=/^[A-Za-z\u00C0-\u017F]{1}$/,u=function(e,t,n){var r=c(t,n)
46+
if(!r)return{hyphen:!1,node:t,offset:n}
47+
var i=r.maxoffset,o=r.originalOffset,a=r.leftNodes.nodes,s=e.call(this,r.word,i)
48+
s=isNaN(s)?i:Math.min(s,i)
49+
for(var h=0==s?!1:d.test(r.word.charAt(s-1)),l=o-s,f=0;f<a.length;f++){var u=a[f],g=0===f?n:u.data.length
50+
if(!(l>g))return{node:u,offset:Math.max(g-l,0),hyphen:h}
51+
l-=g}},c=function(e,t){var r=n.createRange()
52+
if(r.setStart(e,t),r.setEnd(e,t+1),/^\s+$/.test(""+r))return null
53+
var i=h(e,t,r),o=(""+r).length-1,a=o
54+
l(e,t,r)
55+
var s=""+r
56+
return d.test(s.charAt(o-1))&&o--,r.detach(),{word:s,leftNodes:i,maxoffset:o,originalOffset:a}},g=function(e){for(;e;){for(var t,n=!1;t=n||e.previousSibling;){if(e=t,n=!1,3==e.nodeType)return e
57+
1==e.nodeType&&e.lastChild&&(n=e.lastChild)}e=v(e)}return null},p=function(e){for(;e;){for(var t,n=!1;t=n||e.nextSibling;){if(e=t,n=!1,3==e.nodeType)return e
58+
1==e.nodeType&&e.firstChild&&(n=e.firstChild)}e=v(e)}return null},v=function(e){var t=e.parentNode
59+
return t&&1===t.nodeType?t:null},y=function(e){for(var t,n=e.querySelectorAll("span[data-shape-id]"),r=[],i={},o=0,s=n.length;s>o;o++){t=n[o]
60+
var h=t.getAttribute("data-shape-id")
61+
i[h]||(i[h]=!0,r.push(a[h]))}return r},m=function(e){var t=n.createElement("span")
62+
return t.setAttribute("data-shape-id",e),t},C=function(e,t){for(var n=0;n<t.length;n++)if(b(e,t[n].shape))return t[n]
63+
return!1},b=function(e,t){return e.left<=t.right&&t.left<=e.right&&e.top<=t.bottom&&t.top<=e.bottom},A=function(e,t,n,r){var e=N(e,n)
64+
return e?w(e,t,n,r):null},w=function(e,t,r,i){var o
65+
if(3==e.nodeType){for(var a=-1,s=!1,h=n.createRange();a++<e.data.length-1;){h.setStart(e,a),h.setEnd(e,a+1)
66+
var l=f(h.getBoundingClientRect()),d=C(l,r)
67+
if(d){s=!0,o=i.call(d,e,a,l)
68+
break}}h.detach(),s||(o=e)}else if(1==e.nodeType){var l=e.getBoudingClientRect(),d=C(l,r)
69+
o=i.call(d,e,null,l)}return o?(o=T(o,t,r),o?w(o,t,r,i):null):null},R=function(e){var t=e.textContent||e.innerText
70+
return 0===e.children||!t||/^\s*$/.test(t)},S=function(e){return!e.style.position||"static"==e.style.position},E=function(e){var t=e.shape,n=t.left,r=(t.right,f(e.getBoundingClientRect()))
71+
if(t=a[e.getAttribute("data-shape-id")],t&&(t=t.shape),r.left!=n){var i=v(e)
72+
if(i)return i.removeChild(e)}if(t&&!b(r,t)){var i=v(e)
73+
if(i)return i.removeChild(e)}},T=function(e,t,r){for(var i=e,o=null;e!==t&&(e=e.nextSibling||o);)if(o=null,1==e.nodeType)if(R(e)){if(e.hasAttribute("data-shape-id"))o=e.nextSibling,E(e),o=v(e)?null:o
74+
else if(C(f(e.getBoundingClientRect()),r)&&!S(e))return e}else if(C(f(e.getBoundingClientRect()),r)){var a=N(e,r)
75+
if(a)return a}else for(var s=e.querySelectorAll("span[data-shape-id]"),h=0,l=s.length;l>h;h++)E(s[h])
76+
else if(3==e.nodeType){var d=n.createRange()
77+
if(d.selectNodeContents(e),C(f(d.getBoundingClientRect()),r))return d.detach(),e
78+
d.detach()}return i!==t&&v(i)?T(v(i),t,r):null},N=function(e,t){for(var r,i=0,o=e.childNodes,a=o.length;a>i&&(r=o[i],r);i++)if(1==r.nodeType)if(R(r)){if(r.hasAttribute("data-shape-id"))E(r),r||i--
79+
else if(C(f(r.getBoundingClientRect()),t)&&!S(r))return r}else{var s=N(r,t)
80+
if(s)return s}else if(3==r.nodeType){var h=n.createRange()
81+
if(h.selectNodeContents(r),C(f(h.getBoundingClientRect()),t))return h.detach(),r
82+
h.detach()}return null},B={ANYWHERE:function(e,t){return t},HYPHER:function(e){return function(t,n){for(var r,i=e.hyphenate(t),o="",a=0;a<i.length;a++){if(r=i[a],!(r.length+o.length<=n))return o.length
83+
o+=r}return o.length}},NH_ANYWHERE:function(){},NH_WORD:function(e,t){return 0}}
84+
r.forEach=function(e){for(var n in a)if(a.hasOwnProperty(n)){var r=e.call(a[n])
85+
if(!r&&r!==t)break}},r.removeAll=function(e){e=e||n.body
86+
for(var t,r=n.body.querySelectorAll("[data-shape-id]"),i=0;i<r.length;i++){t=r[i]
87+
var o=v(t)
88+
o&&o.removeChild(t)}e=1===e.nodeType?e:n.body,e.normalize()},r.refreshAll=function(e){e&&r.removeAll(),r.forEach(function(){this.refresh()})},r.HYPHENATION=B
89+
var H=!0
90+
window.addEventListener("resize",function(){H&&r.refreshOnResize&&(H=!1,window.requestAnimationFrame(function(){r.refreshAll(!0),H=!0}))},!1),r.changeDefaultHyphenCharacter=function(e){_.rules[0].style.content='"'+e+'"'},r.version="0.1a",r.build="100",r.refreshOnResize=!0
91+
var x=n.createElement("style")
92+
n.head.appendChild(x)
93+
var _=x.sheet
94+
_.insertRule(".SHAPE-hyphen::before { content:'-'; }",0),window.SHAPE=r}()

0 commit comments

Comments
 (0)