| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| package flashx.textLayout.property |
| { |
| import flash.text.engine.TabAlignment; |
| |
| import flashx.textLayout.debug.assert; |
| import flashx.textLayout.formats.FormatValue; |
| import flashx.textLayout.formats.TabStopFormat; |
| |
| [ExcludeClass] |
| /** Property for tab stops. Extends ArrayProperty; setter takes a string representation of tab stops in addition to an array. @private */ |
| public class TabStopsProperty extends ArrayProperty |
| { |
| public function TabStopsProperty(nameValue:String, defaultValue:Array, inherited:Boolean, categories:Vector.<String>) |
| { |
| super(nameValue, defaultValue, inherited, categories, TabStopFormat); |
| } |
| |
| /** Helper function when setting the property */ |
| public override function setHelper(currVal:*,newVal:*):* |
| { |
| // null is a real value - DO NOT map to undefined like the others |
| |
| // null, undefined and INHERIT are all valid for arrays |
| if (newVal == null || newVal == FormatValue.INHERIT) |
| return newVal; |
| |
| // Accepts either an array or a string representation |
| var tabStops:Array = newVal as Array; |
| if (tabStops) |
| { |
| if (!checkArrayTypes(tabStops)) |
| { |
| Property.errorHandler(this,newVal); |
| return currVal; |
| } |
| } |
| else |
| { |
| var valString:String = newVal as String; |
| if (!valString) |
| { |
| Property.errorHandler(this,newVal); |
| return currVal; |
| } |
| |
| // Parse the string representation and create an equivalent array |
| tabStops = new Array(); |
| |
| // Replace escape sequences (\ followed by a space or \) with placeholder strings |
| // that can't naturally occur in the passed-in string |
| valString = valString.replace(_escapeBackslashRegex, _backslashPlaceHolder); |
| valString = valString.replace(_escapeSpaceRegex, _spacePlaceHolder); |
| |
| _tabStopRegex.lastIndex = 0; |
| do |
| { |
| var result:Object = _tabStopRegex.exec(valString); |
| if (!result) |
| break; // no more matches |
| |
| var tabStop:TabStopFormat = new TabStopFormat(); |
| switch (result[1].toLowerCase()) |
| { |
| case "s": |
| case "": // START is the default |
| tabStop.alignment = TabAlignment.START; |
| break; |
| case "c": |
| tabStop.alignment = TabAlignment.CENTER; |
| break; |
| case "e": |
| tabStop.alignment = TabAlignment.END; |
| break; |
| case "d": |
| tabStop.alignment = TabAlignment.DECIMAL; |
| break; |
| } |
| |
| var position:Number = Number(result[2]); |
| if (isNaN(position)) |
| { |
| Property.errorHandler(this,newVal); |
| return currVal; |
| } |
| tabStop.position = position; |
| |
| if (tabStop.alignment == TabAlignment.DECIMAL) |
| { |
| if (result[3] == "") |
| tabStop.decimalAlignmentToken = "."; //default |
| else |
| { |
| // strip the leading vertical bar and restore \ and space characters where intended |
| tabStop.decimalAlignmentToken = result[3].slice(1).replace(_backslashPlaceholderRegex, "\\"); |
| tabStop.decimalAlignmentToken = tabStop.decimalAlignmentToken.replace(_spacePlaceholderRegex, " "); |
| } |
| } |
| else if (result[3] != "") |
| { |
| Property.errorHandler(this,newVal); |
| return currVal; // if alignment is not decimal, the alignment token is not allowed |
| } |
| |
| tabStops.push(tabStop); |
| |
| } while (true); |
| |
| } |
| |
| return tabStops.sort(compareTabStopFormats); |
| } |
| |
| /** @private */ |
| public override function toXMLString(val:Object):String |
| { |
| var str:String = ""; |
| var tabStops:Array = val as Array; |
| for each (var tabStop:TabStopFormat in tabStops) |
| { |
| if (str.length) |
| str += " "; |
| |
| switch (tabStop.alignment) |
| { |
| case TabAlignment.START: |
| str += "s"; |
| break; |
| case TabAlignment.CENTER: |
| str += "c"; |
| break; |
| case TabAlignment.END: |
| str += "e"; |
| break; |
| case TabAlignment.DECIMAL: |
| str += "d"; |
| break; |
| } |
| |
| str += tabStop.position.toString(); |
| |
| if (tabStop.alignment == TabAlignment.DECIMAL) |
| { |
| var escapedAlignmentToken:String = tabStop.decimalAlignmentToken.replace(_backslashRegex, "\\\\"); |
| escapedAlignmentToken = escapedAlignmentToken.replace(_spaceRegex, "\\ "); |
| str += "|" + escapedAlignmentToken; |
| } |
| } |
| |
| return str; |
| } |
| |
| private static function compareTabStopFormats(a:TabStopFormat, b:TabStopFormat):Number |
| { |
| return a.position == b.position ? 0 : a.position < b.position ? -1 : 1; |
| } |
| |
| // Alignment type: [sScCeEdD]? - Atmost 1 occurance of one of s/c/e/d (or upper-case equivalents) |
| // Position: [^| ]+ - At least character which is not a space or | (further validation is done by the Number constructor) |
| // Alignment token and separator:(|[^ ]*)? - Atmost one occurance of a | followed by 0 or more non-space characters |
| // Delimiter: ( |$) - A space or end-of-string |
| private static const _tabStopRegex:RegExp = /([sScCeEdD]?)([^| ]+)(|[^ ]*)?( |$)/g; |
| private static const _escapeBackslashRegex:RegExp = /\\\\/g; |
| private static const _escapeSpaceRegex:RegExp = /\\ /g; |
| private static const _backslashRegex:RegExp = /\\/g; |
| private static const _spaceRegex:RegExp = / /g; |
| private static const _backslashPlaceholderRegex:RegExp = /\uE000/g; |
| private static const _spacePlaceholderRegex:RegExp = /\uE001/g; |
| |
| // Replace escape sequences (\ followed by a space or \) with placeholder strings |
| // containing characters from Unicode private use area (won't naturally occur in the passed-in string) |
| private static const _backslashPlaceHolder:String = String.fromCharCode(0xE000); |
| private static const _spacePlaceHolder:String = String.fromCharCode(0xE001); |
| |
| } |
| } |