stylist.js
来自「Hippo CMS是一个以信息为中心的开源内容管理系统。Hippo CMS目标是」· JavaScript 代码 · 共 542 行 · 第 1/2 页
JS
542 行
/**
* Add an empty css_style to Config object's prototype
* the format is { '.className' : 'Description' }
*/
HTMLArea.Config.prototype.css_style = { };
/**
* This method loads an external stylesheet and uses it in the stylist
*/
HTMLArea.Config.prototype.stylistLoadStylesheet = function(url, altnames)
{
if(!altnames) altnames = { };
var newStyles = HTMLArea.ripStylesFromCSSFile(url);
for(var i in newStyles)
{
if(altnames[i])
{
this.css_style[i] = altnames[i];
}
else
{
this.css_style[i] = newStyles[i];
}
}
this.pageStyleSheets[this.pageStyleSheets.length] = url;
};
/**
* This method takes raw style definitions and uses them in the stylist
*/
HTMLArea.Config.prototype.stylistLoadStyles = function(styles, altnames)
{
if(!altnames) altnames = { };
var newStyles = HTMLArea.ripStylesFromCSSString(styles);
for(var i in newStyles)
{
if(altnames[i])
{
this.css_style[i] = altnames[i];
}
else
{
this.css_style[i] = newStyles[i];
}
}
this.pageStyle += styles;
};
/**
* Fill the stylist panel with styles that may be applied to the current selection. Styles
* are supplied in the css_style property of the HTMLArea.Config object, which is in the format
* { '.className' : 'Description' }
* classes that are defined on a specific tag (eg 'a.email_link') are only shown in the panel
* when an element of that type is selected.
* classes that are defined with selectors/psuedoclasses (eg 'a.email_link:hover') are never
* shown (if you have an 'a.email_link' without the pseudoclass it will be shown of course)
* multiple classes (eg 'a.email_link.staff_member') are shown as a single class, and applied
* to the element as multiple classes (class="email_link staff_member")
* you may click a class name in the stylist panel to add it, and click again to remove it
* you may add multiple classes to any element
* spans will be added where no single _and_entire_ element is selected
*/
HTMLArea.prototype._fillStylist = function()
{
if(!this._stylist) return false;
this._stylist.innerHTML = '<h1>'+HTMLArea._lc('Styles', 'Stylist')+'</h1>';
var may_apply = true;
var sel = this._getSelection();
// What is applied
// var applied = this._getAncestorsClassNames(this._getSelection());
// Get an active element
var active_elem = this._activeElement(sel);
for(var x in this.config.css_style)
{
var tag = null;
var className = x.trim();
var applicable = true;
var apply_to = active_elem;
if(applicable && /[^a-zA-Z0-9_.-]/.test(className))
{
applicable = false; // Only basic classes are accepted, no selectors, etc.. presumed
// that if you have a.foo:visited you'll also have a.foo
// alert('complex');
}
if(className.indexOf('.') < 0)
{
// No class name, just redefines a tag
applicable = false;
}
if(applicable && (className.indexOf('.') > 0))
{
// requires specific html tag
tag = className.substring(0, className.indexOf('.')).toLowerCase();
className = className.substring(className.indexOf('.'), className.length);
// To apply we must have an ancestor tag that is the right type
if(active_elem != null && active_elem.tagName.toLowerCase() == tag)
{
applicable = true;
apply_to = active_elem;
}
else
{
if(this._getFirstAncestor(this._getSelection(), [tag]) != null)
{
applicable = true;
apply_to = this._getFirstAncestor(this._getSelection(), [tag]);
}
else
{
// alert (this._getFirstAncestor(this._getSelection(), tag));
// If we don't have an ancestor, but it's a div/span/p/hx stle, we can make one
if(( tag == 'div' || tag == 'span' || tag == 'p'
|| (tag.substr(0,1) == 'h' && tag.length == 2 && tag != 'hr')))
{
if(!this._selectionEmpty(this._getSelection()))
{
applicable = true;
apply_to = 'new';
}
else
{
// See if we can get a paragraph or header that can be converted
apply_to = this._getFirstAncestor(sel, ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']);
if(apply_to != null)
{
applicable = true;
}
}
}
else
{
applicable = false;
}
}
}
}
if(applicable)
{
// Remove the first .
className = className.substring(className.indexOf('.'), className.length);
// Replace any futher ones with spaces (for multiple class definitions)
className = className.replace('.', ' ');
if(apply_to == null)
{
if(this._selectionEmpty(this._getSelection()))
{
// Get the previous element and apply to that
apply_to = this._getFirstAncestor(this._getSelection(), null);
}
else
{
apply_to = 'new';
tag = 'span';
}
}
}
var applied = (this._ancestorsWithClasses(sel, tag, className).length > 0 ? true : false);
var applied_to = this._ancestorsWithClasses(sel, tag, className);
if(applicable)
{
var anch = document.createElement('a');
anch._stylist_className = className.trim();
anch._stylist_applied = applied;
anch._stylist_appliedTo = applied_to;
anch._stylist_applyTo = apply_to;
anch._stylist_applyTag = tag;
anch.innerHTML = this.config.css_style[x];
anch.href = 'javascript:void(0)';
var editor = this;
anch.onclick = function()
{
if(this._stylist_applied == true)
{
editor._stylistRemoveClasses(this._stylist_className, this._stylist_appliedTo);
}
else
{
editor._stylistAddClasses(this._stylist_applyTo, this._stylist_applyTag, this._stylist_className);
}
return false;
}
anch.style.display = 'block';
anch.style.paddingLeft = '3px';
anch.style.paddingTop = '1px';
anch.style.paddingBottom = '1px';
anch.style.textDecoration = 'none';
if(applied)
{
anch.style.background = 'Highlight';
anch.style.color = 'HighlightText';
}
this._stylist.appendChild(anch);
}
}
};
/**
* Add the given classes (space seperated list) to the currently selected element
* (will add a span if none selected)
*/
HTMLArea.prototype._stylistAddClasses = function(el, tag, classes)
{
if(el == 'new')
{
this.insertHTML('<' + tag + ' class="' + classes + '">' + this.getSelectedHTML() + '</' + tag + '>');
}
else
{
if(tag != null && el.tagName.toLowerCase() != tag)
{
// Have to change the tag!
var new_el = this.switchElementTag(el, tag);
if(typeof el._stylist_usedToBe != 'undefined')
{
new_el._stylist_usedToBe = el._stylist_usedToBe;
new_el._stylist_usedToBe[new_el._stylist_usedToBe.length] = {'tagName' : el.tagName, 'className' : el.getAttribute('class')};
}
else
{
new_el._stylist_usedToBe = [{'tagName' : el.tagName, 'className' : el.getAttribute('class')}];
}
HTMLArea.addClasses(new_el, classes);
}
else
{
HTMLArea._addClasses(el, classes);
}
}
this.focusEditor();
this.updateToolbar();
};
/**
* Remove the given classes (space seperated list) from the given elements (array of elements)
*/
HTMLArea.prototype._stylistRemoveClasses = function(classes, from)
{
for(var x = 0; x < from.length; x++)
{
this._stylistRemoveClassesFull(from[x], classes);
}
this.focusEditor();
this.updateToolbar();
};
HTMLArea.prototype._stylistRemoveClassesFull = function(el, classes)
{
if(el != null)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?